状态管理React上下文api与redux

Modern front-end frameworks like React, Vue, and Angular has changed the way our web looks like today. A maximum of them are using a component-based approach. But communication among the components is an important part. The way components communicate and share state with each other, defines their success story. To create maintainable software by separating different parts of logic and state into dedicated components is a bit tricky.

像React,Vue和Angular这样的现代前端框架已经改变了我们的网络今天的样子。 他们中的大多数使用基于组件的方法。 但是组件之间的通信是重要的一部分。 组件之间相互交流和共享状态的方式定义了它们的成功故事。 通过将逻辑和状态的不同部分分成专用组件来创建可维护的软件有些棘手。

Passing data to deeply nested child components can be cumbersome, especially when dealing with child components several levels down a component tree. Without React Context or Redux, we resort to a technique called “prop drilling” where we pass data down components even though some of those components don’t need that specific data.

将数据传递到深度嵌套的子组件可能很麻烦,尤其是在处理组件树下几层的子组件时。 在没有React ContextRedux的情况下,我们诉诸一种称为“钻探”的技术,该技术将数据向下传递到各个组件,即使其中一些组件不需要该特定数据。

使用React上下文 (Using React Context)

Context in React allows you to pass data to any component without “prop drilling”. Also, it is possible to update the context data from any subscribed component.

React中的上下文使您可以将数据传递到任何组件,而无需“专业钻探”。 同样,可以从任何订阅的组件更新上下文数据。

We will use a simple example that will help us to understand the main concept of Context.

我们将使用一个简单的示例来帮助我们理解上下文的主要概念。

First of all, we will create a context for user data.

首先,我们将为用户数据创建一个上下文。

So create a file UserContext.js in the root of /src folder

因此,在/ src文件夹的根目录中创建一个文件UserContext.js

import React, { createContext, useState } from "react";


export const UserContext = createContext();


// This context provider is passed to any component requiring the context
export const UserProvider = ({ children }) => {
  const [name, setName] = useState("Manash");
  const [profession, setProfession] = useState("Sr. Software Engineer");


  return (
    <UserContext.Provider value={{name, profession, setName, setProfession}}>
        {children}
    </UserContext.Provider>
  );
};

Here, data are passed via the value props to any subscriber of the provider.

在这里,数据通过value道具传递给提供者的任何订户。

Then wrap the App component with UserContext in the index.js file

然后将App组件与UserContext一起包装在index.js文件中

import React from 'react';
import ReactDOM from 'react-dom';
import { UserProvider } from './UserContext';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';


ReactDOM.render(
    <UserProvider>
        <App />
    </UserProvider>,
  document.getElementById('root')
);


// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

Wow, we are almost done. Now the Context is ready to be used. To use these context data need to import useContext hook in the components. So here are our components look like.

哇,我们快完成了。 现在可以使用上下文了。 要使用这些上下文数据,需要在组件中导入useContext钩子。 因此,这是我们的组件外观。

import React from 'react';
import ShowContextData from './components/showContextData';
import UpdateContextData from './components/updateContextData';
import './App.css';


const App = () => {
  return (
    <div className="App">
      <h1>React Context Example</h1>
      <UpdateContextData />      
      <hr/> 
      <ShowContextData />          
    </div>
  );
}


export default App;
import React, { useContext } from 'react';
import { UserContext } from '../UserContext';


const ShowContextData = () => {
    const user = useContext(UserContext);
    return (
        <div>
            <h3>
            Showing from context
            </h3>
            <strong>Name</strong>: {user.name}<br/>
            <strong>Profession</strong>: {user.profession}
        </div>
    );
};


export default ShowContextData;
import React, { useContext } from 'react';
import { UserContext } from '../UserContext';


const UpdateContextData = () => {
    const user = useContext(UserContext);
    return (
        <div>
            <h3>Update context data</h3>
            <div className="form-group">
                <label>Name</label>
                <input type="text" className="form-control" value={user.name} onChange={e => user.setName(e.target.value)} />
            </div>
            <div className="form-group">
                <label>Profession</label>
                <input type="text" className="form-control" value={user.profession} onChange={e => user.setProfession(e.target.value)} />
            </div>
        </div>
    );
};


export default UpdateContextData;

So finally we have used context data & update as well. Its really simple, right?

所以最后我们也使用了上下文数据和更新。 它真的很简单,对吧?

You will find full source code here.

Ÿ欧可以找到完整的源代码 在这里

使用Redux (Using Redux)

It’s a predictable state container for JavaScript apps. The whole state of your app is stored in an object tree inside a single store. The only way to change the state tree is to emit an action, an object describing what happened. To specify how the actions transform the state tree, you have to write pure reducers.

这是JavaScript应用程序的可预测状态容器。 应用程序的整个状态存储在单个商店内的对象树中。 更改状态树的唯一方法是发出一个action ,一个描述发生了什么的对象。 要指定动作如何转换状态树,您必须编写pure reducers

We will try to show some simple actions and reducers, required to manage the state using redux. So we will keep & update some user data in the redux state.

我们将尝试展示一些使用redux管理状态所需的简单操作和化简。 因此,我们将在Redux状态下保持并更新一些用户数据。

First we have to install few packages

首先,我们必须安装一些软件包

npm install redux

npm install redux

npm install react-redux

npm install react-redux

npm install redux-persist

npm install redux-persist

Now we need to create some redux related files & keep it in a separate folder, we are naming it redux. Inside this folder we will create below files.

现在我们需要创建一些与redux相关的文件并将其保存在单独的文件夹中,我们将其命名为redux 。 在此文件夹中,我们将创建以下文件。

export const ADD_USER_DATA = "ADD_USER_DATA";
import {ADD_USER_DATA} from "./actionTypes";


export const addUserData = user => ({
    type: ADD_USER_DATA,
    payload: {
        user
    }
});
import { createStore } from "redux";
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import rootReducer from "./reducers";


const persistConfig = {
    key: 'root',
    storage: storage
};


const pReducer = persistReducer(persistConfig, rootReducer);


export const store = createStore(pReducer);
export const persistor = persistStore(store);

In /redux/reducers/ create a reducer for adding user data

在/ redux / reducers /中创建用于添加用户数据的reducer

import {ADD_USER_DATA} from "../actionTypes";


const initialState = {
    user: null
};
const User = (state = initialState, action) => {
    switch (action.type) {
        case ADD_USER_DATA: {
            const { user } = action.payload;
            return {
                ...state,
                user: user
            };
        }
        default:
            return state;
    }
}


export default User;

Combine all reducer, though we have only one reducer, but we are following a convention to adapt more reducers later.

合并所有减速器,尽管我们只有一个减速器,但是我们遵循的惯例是以后再适配更多减速器。

import { combineReducers } from "redux";
import User from "./user";


export default combineReducers({ User });

Now we have to connect Redux with React. First, we need to make the store available to our app. To do this, we wrap our app with the <Provider />API provided by React-Redux.

现在我们必须将Redux与React连接起来。 首先,我们需要使store可用于我们的应用程序。 为此,我们使用React-Redux提供的<Provider /> API包装我们的应用<Provider />

import React from 'react';
import ReactDOM from 'react-dom';
/** Redux */
import { Provider } from 'react-redux';
import { persistor, store } from "./redux/store";
import { PersistGate } from 'redux-persist/integration/react';
/** End */
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';


ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <App />
      </PersistGate>
    </Provider>    
  </React.StrictMode>,
  document.getElementById('root')
);


// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

React-Redux provides a connect function for you to read values from the Redux store.

React-Redux提供了一个connect函数供您从Redux存储中读取值。

The connect function takes two arguments, both optional:

connect函数带有两个参数,两个参数都是可选的:

  • mapStateToProps: called every time the store state changes. It receives the entire store state and should return an object of data this component needs.

    mapStateToProps :每次存储状态更改时调用。 它接收整个存储状态,并应返回此组件需要的数据对象。

  • mapDispatchToProps: This parameter can either be a function, or an object.

    mapDispatchToProps :此参数可以是函数或对象。

So we are going to use connect in our App component

因此,我们connectApp组件中使用connect

import React, { useState } from 'react';
import './App.css';


import { connect } from 'react-redux';
import { addUserData } from './redux/actions';


const App = ({ user, addUserData }) => {
  const [name, setName] = useState(user != null ? (user.hasOwnProperty('name') ? user.name : '') : '');
  const [profession, setProfession] = useState(user != null ? (user.hasOwnProperty('profession') ? user.profession : '') : '');


  const handleChange = (event) => {
    if(event.target.name == "name"){
      setName(event.target.value);
    }
    if(event.target.name == "profession"){
      setProfession(event.target.value);
    }
  };


  const handleSubmit = (event) => {
    addUserData({name, profession});
  };


  return (
    <div className="App">
      <h1>React Redux Example</h1>
      Name: <input type="text" name="name" value={name} onChange={handleChange} /><br/>
      Profession: <input type="text" name="profession" value={profession} onChange={handleChange} /><br/>
      <button type="submit" onClick={handleSubmit}>Update</button>
    </div>
  );
}


const mapStateToProps = (state) => {
  const {user} = state.User;    
  return {user};
};


export default connect(mapStateToProps, { addUserData })(App);

You will find full source code here.

您将在此处找到完整的源代码。

谁赢? (Who wins?)

It is really a tough question. At a high level, we can say, Redux is far from dead or be killed by React Context & still it is one of the greatest solutions towards props drilling even it requires a bunch of libraries.

这确实是一个棘手的问题。 从较高的层次上讲,Redux并没有被React Context杀死或杀死,即使它需要大量的库,它仍然是Props钻探的最佳解决方案之一。

You already get basic knowledge of Redux and React Context. React Context with hooks is much easier to implement & since it’s built into React and you therefore need no extra third-party dependencies, so total bundle size won’t increase.

您已经获得了Redux和React Context的基础知识。 带钩子的React Context易于实现&,因为它内置在React中,因此您不需要额外的第三方依赖项,因此总包大小不会增加。

So what should we use for our state management?

那么,我们应该使用什么进行状态管理?

For simple or low-frequency updates like theme settings, user authentication data, React Context is the perfect choice. On the other hand for complex or high-frequency update Redux should be used, React Context won’t be a good solution. React Context will trigger a re-render on each update, and optimizing it manually can be really tough.

对于主题设置,用户身份验证数据等简单或低频更新,React Context是理想的选择。 另一方面,对于复杂或高频更新,应该使用Redux,React Context并不是一个好的解决方案。 React Context将在每次更新时触发重新渲染,而手动优化它确实很困难。

Finishing with the comment of Sebastian Markbåge (Facebook React Team)

结束语SebastianMarkbåge (Facebook React团队)的评论

My personal summary is that new context is ready to be used for low frequency unlikely updates (like locale/theme). It’s also good to use it in the same way as old context was used. I.e. for static values and then propagate updates through subscriptions. It’s not ready to be used as a replacement for all Flux-like state propagation. — sebmarkbage

我的个人总结是,新上下文已准备好用于低频不太可能的更新(例如语言环境/主题)。 以与使用旧上下文相同的方式使用它也很好。 即获取静态值,然后通过订阅传播更新。 还没有准备好替代所有类似Flux的状态传播。 —渣包

翻译自: https://medium.com/weekly-webtips/state-management-reacts-context-api-vs-redux-f308e73b495

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值