【问题标题】:How to provide a value to every component?如何为每个组件提供价值?
【发布时间】:2019-09-10 19:27:15
【问题描述】:

我对 React Native 有点陌生。

我正在尝试为每个组件添加一个值,主要是登录信息。

我正在使用这个库:

https://github.com/mahomahoxd/react-native-login-keycloak

您通过这种方式获取登录信息:

import Login from 'react-native-login-keycloak';


const gatheredTokens = await Login.getTokens();

现在很明显,await 需要在异步函数中,所以我尝试如下:

async componentWillMount() {
    const gatheredTokens = await Login.getTokens();
    this.setState({ gatheredTokens: this.state.gatheredTokens });
}

但是这看起来很混乱 - 首先,componentWillMount 显然已被弃用(我想我可以将其切换为 componentDidMount),而且它还需要我在每个组件中基本上复制此过程。乱码重复!

有什么更纯粹的方法来做到这一点?我猜是高阶组件或其他结构?

谁能给我一个例子,说明我将如何向我的所有组件提供这个(我正在使用 Redux,所以通过 Redux 或其他方法很好) - 我只是不确定如何确保数据是处理并在任何需要的地方可用,我想要最“反应”的方式。

【问题讨论】:

  • 您可以从父组件中获取此数据并将其作为道具传递给每个子组件。
  • 如果您使用的是 redux,那么只需设置您的中心状态并将其映射到需要访问数据的任何组件。 redux 文档中有很多示例:redux.js.org/basics/usage-with-react
  • 使用 redux 选择器? mapStateToProps 或将它们作为 prop 从父组件传递下来。
  • @MattAft - 我会在我的 store.js 中还是在单独的 action/reducer 中这样做?你能写一个简单的例子吗?我或多或少了解 Redux,但我才用了几个月
  • 如果您希望能够修改状态值,则需要设置一个动作/减速器。我提供的链接为您提供了一个简单的待办事项应用程序的示例。问题是如果应用程序关闭以自动登录,您是否希望保存它?因为那样你就可以使用 RN 的异步存储了:facebook.github.io/react-native/docs/asyncstorage

标签: javascript reactjs react-native


【解决方案1】:

有多种方法可以做到这一点,渲染 Props、高阶组件,甚至是钩子——不确定在我写这个钩子的时候 React Native 是否支持。

既然你建议了一个高阶组件,那么我的解决方案将使用一个

export const withGatheredTokens = Component => {
  class WithGatheredTokens extends React.Component {
    state = { gatheredTokens: null };

    async componentDidMount() {
        const gatheredTokens = await Login.getTokens();
        this.setState({ gatheredTokens });
    }

    render() {
      return (
        <Component gatheredTokens={this.state.gatheredTokens} {...props} />
      );
    }
  }

  return WithGatheredTokens;
};

// And this is how you use with with a Another Component
export AnotherComponent =  withGatheredTokens(AnotherComponentBase)

无论如何,网络请求应始终在 ComponendDidUpdate 中完成,而不是在 componentWillMount 方法中。

【讨论】:

  • 我相信你的意思是这条线是 this.setState({ gatherTokens:gatheredTokens });
  • @CecilRodriguez 是的,这是真的,我编辑了我的答案。你也可以在这里使用 es6 速记属性来使代码更小(我在我的编辑中这样做了)
  • @ehab 不错。我认为这将以某种方式起作用,对于我进入的每个具有我导入组件的屏幕,如果 Login.getToken 未完成,它将一遍又一遍地调用 componentDidMount 函数
  • @OluwasayoBabalola 不,componentDidMount 在组件安装时仅被调用一次(除非组件被卸载并再次重新安装)。然而,在获取数据之前,Wrapped 组件将接收到的收集标记为 null(我们指定的初始状态),并且一旦获取数据,HigherOrderComponent 将重新渲染为其子项的新值 collecttokens跨度>
  • @ehab 对,明白。 componentDidMount 只被调用一次。有趣的!将进一步阅读此 +1
【解决方案2】:

使用 Redux

创建您的 actionsreducers

//你可以用

将你的动作文件命名为 loginAction.js
export const setLoginData = data => {
  return {
    type: SET_LOGIN_TOKEN,
    payload: data
  }
};

//和你的减速器

export default (state = {}, action = {}) => {
   switch (action.type) {
      case SET_LOGIN_DATA:
         return {...state, loginData: action.payload};

      default:
        return state;
   }
}

//不要忘记将您的商店应用到App.js 包装View 与//

使用 登录时获得令牌

async componentDidMount() {
   const gatheredTokens = await Login.getTokens();
   this.setState({ gatheredTokens: gatheredTokens });
   //this.setLoginData(gatheredTokens); 
   //having imported `setLoginData` from your login action, and also used `mapDispatchToProps`
}

那么你的 loginData 应该在你需要的任何地方都可用

const mapStateToProps = (state) => ({
   loginData: state.loginData,
});

然后你可以在 loginData 中访问令牌

const loginToken = this.props.loginData;

【讨论】:

  • 您会说这种方法还是 HOC 方法“更好”?
  • 我相信两者都可以。这取决于哪个最适合您的用例。 @CecilRodriguez
猜你喜欢
  • 2016-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-10
相关资源
最近更新 更多