React Native 中的全局状态

Posted

技术标签:

【中文标题】React Native 中的全局状态【英文标题】:Global state in React Native 【发布时间】:2017-10-28 20:41:46 【问题描述】:

我正在开发一个 React Native 应用程序。

我想保存登录人的用户 ID,然后检查用户是否在每个组件中都登录。

所以我正在寻找类似 cookie、会话或全局状态的东西。

我已经读过我应该使用 Redux,但这似乎过于复杂,并且很难使其与 react-navigation 一起使用。它迫使我为几乎所有东西定义动作和减速器,尽管我唯一想要的是能够访问所有组件中的单个全局状态/变量。

是否有任何替代方案,或者我真的应该重新构建我的整个应用程序以使用 Redux?

【问题讨论】:

我不认为拥有多个商店是一种罪过,在这种情况下,商店是包含一个值(或对象或数组或其他)的东西,并在以下情况下向所有订阅的侦听器提供更改通知存储的数据被修改。 React 组件中有诸如上下文变量之类的替代方案,但我认为从长远来看,您可能会发现 redux 更加结构化且易于管理(和测试)。一开始看起来确实令人生畏,但你很快就会意识到这并不多。 【参考方案1】:

我通常会创建一个 global.js,其中包含:

module.exports = 
   screen1: null,
;

并获取屏幕上状态的值

import GLOBAL from './global.js'

constructor() 

    GLOBAL.screen1 = this;


现在你可以像这样在任何地方使用它:

GLOBAL.screen1.setState(
    var: value
);

【讨论】:

这是最好的;不要小看它的简单。我一直在摆弄 Redux,只是为了获得基本相同的功能,但代码是 20 倍,还有很多魔法(connect 的东西真的很垃圾)。 你能不能给出更有力的解释。我不确定你在 render()Global.screen1state = this 中做了什么 this不是指react组件吗?如果是这样,更好的名称是GLOBAL.screen1 = this,因为这是组件,this.state 实际上是指与组件关联的状态。 @RaphaelEstrada 我是新手。函数组件如何做到这一点? 功能组件怎么样【参考方案2】:

自 React 16.8.0(2019 年 2 月 6 日)以来的更新引入了 Hooks。

不强制使用MobxRedux 等外部库。 (在介绍 Hook 之前,我使用了这两种状态管理解决方案)

您只需使用 10 行 Source 即可创建全局状态

import React, createContext, useContext, useReducer from 'react';
export const StateContext = createContext();
export const StateProvider = (reducer, initialState, children) =>(
  <StateContext.Provider value=useReducer(reducer, initialState)>
    children
  </StateContext.Provider>
);
export const useStateValue = () => useContext(StateContext);

使用全局状态扩展您的应用:

import  StateProvider  from '../state';

const App = () => 
  const initialState = 
    theme:  primary: 'green' 
  ;

  const reducer = (state, action) => 
    switch (action.type) 
      case 'changeTheme':
        return 
          ...state,
          theme: action.newTheme
        ;

      default:
        return state;
    
  ;


  return (
    <StateProvider initialState=initialState reducer=reducer>
        // App content ...
    </StateProvider>
  );

详细解释我推荐阅读这篇精彩的medium

【讨论】:

上下文适用于 ReactJS。【参考方案3】:

在状态管理方面有一些alternatives to Redux。我建议你看看连身衣和 Mobx。但是不要指望它们比 Redux 更容易。状态管理主要是一件神奇的事情,大部分小发明都发生在幕后。

但无论如何,如果您觉得需要一些全局状态管理,那么无论 Redux 还是 Mobx 等,都值得您花时间掌握其中一种解决方案。我不建议为此目的使用 AsyncStorage 或任何 hacky。

【讨论】:

AsyncStorage这样的组件是为了持久化,我认为OP关心的是管理应用程序的状态,通常应该在内存中。 @sooper ,这就是我不推荐AsyncStorage的原因。 状态管理本质上并不神奇。它可以超级简单,同时在没有任何幕后工作的情况下最大限度地发挥作用,请参阅@RaphaelEstrada 的上述答案。当单个 javascript 对象可以同样有效地完成工作时,您建议使用整个代码库,其中大部分您永远不会使用。【参考方案4】:

我通常这样做全局变量:

我创建了一个 globals.js

module.exports = 
  USERNAME: '',
;

类似的东西来存储用户名然后你只需要导入:

GLOBAL = require('./globals');

如果您想存储数据,假设您想保存用户名,只需这样做:

var username = 'test';
GLOBAL.USERNAME = username;

你去,你只需要在你想要的页面上导入GLOBAL并使用它,只需使用if (GLOBAL.username == 'teste')

【讨论】:

这种方式不能正常工作,不会触发像this.state这样的变化 这种方式部分好。它只适用于存储大部分保持不变的东西(例如登录状态)。特别是因为更改这些内容不会重新渲染组件(尽管可以克隆道具)。【参考方案5】:

如果您(像我一样)不熟悉反应并且对第一个答案感到困惑。 首先,使用一个组件类

export default class App extends React.Component 

constructor(props) 
  super(props);
  this.state = 
    walk: true
  ;
  GLOBAL.screen1 = this;


render() 
  return (
    <NavigationContainer>
      <Stack.Navigator>
      this.state.walk ? (
        <>
          <Stack.Screen name="WalkThrough" component=WalkThroughScreen />
        </>
      ) : (
        <Stack.Screen name="Home" component=HomeScreen />
      )
    </Stack.Navigator>
    <StatusBar style="auto" />
  </NavigationContainer>
 )

然后你可以在任何其他组件中做(我的组件在/components,全局在root):

import GLOBAL from '../global.js'

GLOBAL.screen1.setState(walk:false)

【讨论】:

【参考方案6】:

似乎有一个 GLOBAL 对象。如果在 app.js 中设置为 GLOBAL.user = user,它似乎在其他组件中可用,例如抽屉导航。

【讨论】:

【参考方案7】:

这是一个老问题,但我有一个可以帮助我的解决方案。

为了实现这一点,我使用了所谓的 GlobalProvider,它本质上为所有组件提供了全局数据。很多代码都是通过 YouTube 教程学习的,所以我不能把这些想法归功于自己。这是代码,

export const GlobalContext = createContext();

const GlobalProvider = (children) => 
    //authInitialState can be whatever you want, ex: rand: , rand2: null
    const [authState, authDispatch] = useReducer(auth, authInitialState);

    return (
        <GlobalContext.Provider
            value=authState, authDispatch>
            children
        </GlobalContext.Provider>
    );
;

export default GlobalProvider;

然后,您只需使用 GlobalProvider 包装整个应用程序(通常是 app.js)即可。忽略我的 AppNavContainer,它只包含路由我的页面的代码。

import GlobalProvider from "./src/Context/Provider";
const App: () => Node = () => 
    return (
        <GlobalProvider>
            <AppNavContainer/>
        </GlobalProvider>
    );
;

从这里开始,您可以使用某种 reducer 更改 authState,我不会提供该代码,因为它很大,但请看 Soullivaneuh 在上面的 reducer 上的示例。

现在开始介绍如何访问您的状态。很简单,在你想要的任何组件中,只需遵循类似这样的结构即可。请注意,我有 data,因为它可以让您看到状态。

    const 
        authState: data,
     = useContext(GlobalContext);
    
    console.log("Data:", data)

如果有人能纠正我的错误,我也将不胜感激。

【讨论】:

以上是关于React Native 中的全局状态的主要内容,如果未能解决你的问题,请参考以下文章

React Native,全局使用状态?

React Native 中带有 React Hooks 的基本全局状态

React Native 中的全局变量/常量

React Native 中的全局 unhandledrejection 监听器

保存 TextInput 数组的状态 - React Native

React Native中的全局未处理注释侦听器