简介:Redux需要大量的代码,给我们的代码库带来了很多复杂性。充其量,这使其成为React应用程序中状态管理的不完善解决方案。但是,太多的React开发人员默认使用Redux进行状态管理,而没有考虑其他
在本文中,我将介绍用于状态管理的React Context API,并向您展示什么使React Hooks和Context API成为比Redux更好的解决方案。
为什么我们需要状态管理工具
在典型的React中,处理断开的组件之间的数据的方法是通过钻探。例如,由于您不希望组件从顶级组件传递数据到第五级组件,因此组件无法访问全局状态,因此必须将数据作为道具传递给树的每个级别直到找到所需的组件。
这导致编写大量额外的代码,并为组件提供永远不会使用的属性,这也会影响其体系结构设计。为了解决这个问题,我们需要一种方法来提供一个全局状态,所有组件(无论它们嵌套的深度如何)都可以访问。
通过解决这个问题,用于管理应用程序状态的开源JavaScript库Redux成为了React开发人员的首选解决方案。
Redux如何工作
在终极版文档描述它为JavaScript应用程序可预测的状态容器,可以帮助我们,其行为一致,在不同的环境中运行,并且很容易将试写的应用程序。
zheyzh
钻探的一个缺点是需要编写大量额外的代码才能访问顶级组件中的数据。使用Redux,由于为我们的应用程序设置全局状态所需的所有额外代码都带来了许多复杂性,因此甚至感觉到了这种劣势。Redux需要三个主要的构建部分来起作用:actions, reducers, 和 store.。
Actions
这些是用于将数据发送到Redux存储的对象。它们通常具有两个属性:用于描述操作作用的类型属性和包含应在应用程序状态下更改的信息的有效负载属性。
// action.js
const reduxAction = payload => {
return {
type: 'action description',
payload
}
};
export default reduxAction;
type
通常为全部大写,以其字分离用下划线。例如,SIGNUP_USER
或DELETE_USER_DATA
。
Reducers
这些是实现动作行为的纯函数。他们采用当前应用程序状态,执行操作,然后返回新状态:
const reducer = (state, action) => {
const { type, payload } = action;
switch(type){
case "action type":
return {
["action description"]: payload
};
default:
return state;
}
};
export default reducer;
Store
import { createStore } from 'redux'
const store = createStore(componentName);
由于我们的应用程序只能有一个Redux存储,因此为了为我们的所有组件创建单个root reducer,我们将需要combineReducers
Redux中的方法。
通过如此漫长的过程以及设置Redux所需的大量代码,请想象一下,当我们有多个组件要使用时,我们的代码库将是什么样。尽管Redux解决了我们的状态管理问题,但使用起来确实很耗时,学习曲线很困难,并且给我们的应用程序带来了全新的复杂性。
幸运的是,React Context API解决了这个问题。当与React Hooks结合使用时,我们拥有一种状态管理解决方案,该解决方案的建立时间更少,学习曲线也很容易,并且所需的代码最少。
React Context API
新的Context API随React 16.3一起提供。这是React文档中解释上下文的方式:
上下文提供了一种通过组件树传递数据的方法,而不必在每个级别手动传递道具。
React上下文API是React在未直接连接的多个组件中管理状态的方式。
为了创建一个上下文,我们将使用createContext
React 的方法,该方法接受一个参数作为其默认值:
import React from 'react';
const newContext = React.createContext({ color: 'black' });
该createContext
方法返回带有Provider
和的对象Consumer
:
const { Provider, Consumer } = newContext;
该Provider
组件是什么提供给所有子组件的状态,无论多么深嵌套他们是在组件层次结构中。所述Provider
组件接收一个value
。这是我们传递当前值的地方:
<Provider value={color: 'blue'}>
{children}
</Provider>
的Consumer
,顾名思义,消耗来自数据Provider
:
<Consumer>
{value => <span>{value}</span>}}
</Consumer>
果没有Hooks,与Redux相比,Context API看起来可能并不多,但是与useReducer
Hook结合使用,我们就有了可以最终解决状态管理问题的解决方案。
React中的hooks是什么?
是一种功能,可以在基本代码中执行自定义代码。在React中,Hooks是特殊功能,可让我们“了解”其核心功能。
React Hooks通过允许我们轻松处理功能组件的状态管理,提供了一种替代编写基于类的组件的方法。
useContext
Hook
如果您注意到了,在解释React Context API时,我们需要将内容包装在一个Consumer
组件中,然后以子代形式传递一个函数,以便我们可以访问(或使用)状态。这引入了不必要的组件嵌套,并增加了代码的复杂性。
该useContext
Hook使事情要好很多,直接。为了使用它访问我们的状态,我们要做的就是以我们创建context
的参数作为参数来调用它:
const newContext = React.createContext({ color: 'black' });
const value = useContext(newContext);
console.log(value); // this will return { color: 'black' }
现在,无需将内容包装在Consumer
组件中,我们只需通过value
变量访问状态即可。
useReducer
Hook
就像JavaScript中的方法一样,Hook接收两个值作为其参数(在本例中为当前状态和一个动作),然后返回一个新状态:reduce()useReducer
const [state, dispatch] = useReducer((state, action) => {
const { type } = action;
switch(action) {
case 'action description':
const newState = // do something with the action
return newState;
default:
throw new Error()
}
}, []);
在上面的代码块中,我们定义了状态和相应的方法来dispatch
处理它。当我们调用该dispatch
方法时,Hook将根据该方法在其action参数中接收到的内容执行一项操作:useReducer()type
...
return (
<button onClick={() =>
dispatch({ type: 'action type'})}>
</button>
)
实现列子
现在我们知道了Context API和useReducer
Hook分别如何工作,让我们看看将它们结合在一起以为我们的应用程序获得理想的全局状态管理解决方案会发生什么。我们将在文件中创建全局状态:store.js
/ store.js
import React, {createContext, useReducer} from 'react';
const initialState = {};
const store = createContext(initialState);
const { Provider } = store;
const StateProvider = ( { children } ) => {
const [state, dispatch] = useReducer((state, action) => {
switch(action.type) {
case 'action description':
const newState = // do something with the action
return newState;
default:
throw new Error();
};
}, initialState);
return <Provider value={{ state, dispatch }}>{children}</Provider>;
};
export { store, StateProvider }
在我们的文件中,我们使用了前面介绍的方法创建了一个新的上下文。请记住,该方法返回带有和组件的对象。这次,我们只需要使用组件,然后在需要访问状态时使用Hook。store.jscreateContext()
ReactcreateContext() ProviderConsumerProvideruseContext
请注意是如何在应用程序中使用useReducer
Hook的StateProvider
。当我们需要操纵状态时,我们将调用该dispatch
方法并传入一个具有所需type
参数作为参数的对象。
为了全局访问状态,我们需要先将根<App/>
组件包装StoreProvider
在我们的函数中,然后再将其渲染:ReactDOM.render()
// root index.js file
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { StateProvider } from './store.js';
const app = (
<StateProvider>
<App />
</StateProvider>
);
ReactDOM.render(app, document.getElementById('root'));
现在,context
可以从组件树中的任何组件访问我们的store。为此,我们将从文件中导入
// exampleComponent.js
import React, { useContext } from 'react';
import { store } from './store.js';
const ExampleComponent = () => {
const globalState = useContext(store);
console.log(globalState); // this will return { color: red }
};
添加和删除数据
为了从状态中添加和删除数据,我们需要上下文中的dispatch
方法store
。我们只需要调用该dispatch
方法并传入一个对象type
(其动作描述在StateProvider
组件中定义)作为其参数:
// exampleComponent.js
import React, { useContext } from 'react';
import { store } from './store.js';
const ExampleComponent = () => {
const globalState = useContext(store);
const { dispatch } = globalState;
dispatch({ type: 'action description' })
};
结论
在很大程度上,Redux可以在React应用程序中进行状态管理,并且具有一些优势,但是它的冗长性使其难以使用,并且使它在我们的应用程序中运行需要大量的额外代码,这引入了很多不必要的复杂性。
另一方面,使用useContext
API和React Hooks,无需安装外部库或添加大量文件和文件夹即可使我们的应用正常运行。这使它成为处理React应用程序中全局状态管理的更简单,更直接的方法。