是否可以从父上下文访问子上下文?

时间:2019-01-08 16:14:50

标签: reactjs

我对Context有疑问。我有两个上下文,AuthenticationProviderVehiclesProvider

App.tsx

import { AuthenticationProvider, VehiclesProvider } from '../contexts/

export class App extends React.Component {
  public render() {
    return (
      <ThemeProvider theme={theme}>
        <I18nextProvider i18n={i18nConfig}>
          <GlobalStyle />
          <AuthenticationProvider>
            <VehiclesProvider>
              <AppRouter />
            </VehiclesProvider>
          </AuthenticationProvider>
        </I18nextProvider>
      </ThemeProvider>
    )
  }
}

当我们从应用程序注销时,AuthenticationProvider将更新其自身的状态并将其重置为初始状态。但是我们还需要通过AuthenticationProvder中的方法,来重置VehiclesProvider中的状态。

所以我的问题是:是否可以从父上下文访问/修改子上下文中的状态?

AuthenticationProvider.tsx

这是AuthenticationProvider中的方法,应该触发重置子上下文VehiclesProvider

export class AuthenticationProvider extends React.Component<
  IAuthenticationProviderProps,
  IAuthenticationProviderState
> {
  public state = {
    isAuthenticated: false,
    data: undefined,
  }

  // THIS METHOD MUST TRIGGER `resetFetchedVehicles` in `VehiclesContext`
  /**
  * **Update context to logged in state**
  *
  * Save response from API to context. Also let the app know that the user is authenticated.
  *
  * @memberof AuthenticationProvider
  */
  public login = (data: UserClass) => {
    const sameUser = this.isSameUser(data.Id)

    // If it is not the same user, then reset the VehcilesContext
    // if(!sameUser) this.props.resetFetchedVehicles()
    if(sameUser) this.METHODINCHILDCONTEXT.resetFetchedVehicles() // THIS IS WHERE THE STATE IN VEHICLESPROVIDER MUST BE MODIFIED

    this.setState({
      isAuthenticated: true,
      data,
    })
  }

  public render() {
    return (
      <VehiclesConsumer>
        {(context) => (
          <AuthenticationContext.Provider
            value={{
              isAuthenticated: this.state.isAuthenticated,
              data: this.state.data,
              login: this.login,
              logout: this.logout,
              isSameUser: this.isSameUser
            }}
          >
            {this.props.children}
          </AuthenticationContext.Provider>
        )}
      </VehiclesConsumer>
    )
  }
}

VehiclesContext.tsx

export class VehiclesProvider extends React.Component<
  IVehiclesProviderProps,
  IVehiclesProviderState
> {
  public state: IVehiclesProviderState = {
    loading: false,
    fetchedVehicles: [],
    totalVehicles: 0,
  }

  // THIS METHOD MUST BE TRIGGERED FROM `logout` in `AuthenticationContext`
  /**
   * **Remove all the fecthed vehicles from state**
   *
   * @memberof VehiclesProvider
   */
  resetFetchedVehicles = () => {
    this.setState({
      fetchedVehicles: []
    })
  }

  public render() {
    return (
      <VehiclesContext.Provider
        value={{
          loading: this.state.loading,
          fetchedVehicles: this.state.fetchedVehicles,
          fetchVehicles: async () => await this.fetchVehicles(),
          updateUserVehicleInfo: vehicle => this.updateVehicleInfo(vehicle),
          resetFetchedVehicles: () => null
        }}
      >
        {this.props.children}
      </VehiclesContext.Provider>
    )
  }
}

更新

我已经找到了一种方法,可以使用React Context完成我所要求的。这不是推荐的解决方案,因为代码变得非常难看且难以理解。但这有效。我仍然可能会更改为MST / Redux。

对于那些感兴趣的人,这里有一个代码沙箱:嗨! 昨天我问了一个问题,关于是否有可能从父上下文中的方法更新子上下文的状态。我完全理解,现在应该使用React Context。

但是经过很多努力,我找到了一种方法。这是一种骇人听闻的方法,因此可能不建议这样做。如果需要从其他组件更新状态,则应使用Redux或MobxStateTree。

对于那些对如何能够通过partent中的方法更新子上下文感兴趣的人,这里是代码沙箱:https://codesandbox.io/s/kn16859z3

1 个答案:

答案 0 :(得分:1)

也许这不是一个“答案”,但将其添加为注释很大。 我和@Treycos呆在一起。 看起来您正在尝试将上下文用于并非旨在用于其目的。

1)上下文是将状态,道具等传递给子组件的一种方式。

示例:媒体播放器和一个按钮。

MediaPlayer是一个根组件,它了解媒体的所有知识,并且可以播放,暂停,下一个播放等。PlayButton呈现按钮并使用上下文访问根组件的播放功能。您不在乎视觉层次结构。 PlayButton只需位于MediaPlayer内部。

<MediaPlayer>
    <div>
        <div>My Media Player</div>
        <PlayButton>
    </div>
</MediaPlayer>

2)从您的代码看来,您需要管理诸如全局状态之类的东西。为此,您可以使用redux或类似的东西。