react 的全局存储_使用react上下文和钩子模式实现全局存储的第1部分

react 的全局存储

‘Prop Drilling’ through the React component tree is one of the worst nightmares for developers. For those who don’t know what prop drilling is, it’s the process of passing down data/methods from parent to children within a long hierarchy. It’s not a problem when the tree is small, with one or two-level. But when the React component gets larger, it’s troublesome to keep track of all that ‘life-altering’ props.

对React组件树的“支持钻探”是开发人员最糟糕的噩梦之一。 对于那些不知道什么是道具钻探的人,这是在较长的层次结构中将数据/方法从父级传递到子级的过程。 当树很小,只有一两层时,这不是问题。 但是当React组件变大时,要跟踪所有“改变生命”的道具很麻烦。

To solve prop drilling and some related problems, global state management like Redux, Mobx, Unstated, Apollo Link State, etc. has become unrequitedly popular. Also for React, react-redux has become the oneway destination to React developers.

为了解决道具钻探和一些相关问题, ReduxMobxUnstatedApollo Link State等全局状态管理已变得非常流行。 同样对于React来说, react-redux已成为React开发人员的唯一目的地。

But, sometimes for a simple app using those state management solutions might seem overkill. Here comes React to the rescue. Using React Context API and Hook patterns we can create a Redux-like store, that we can use to store data, call on dispatcher for performing actions, and thus solving the problem of prop drilling without installing any third party state management systems. Voila!

但是,有时对于使用这些状态管理解决方案的简单应用程序来说似乎有些过时了。 救援行动来了。 使用React Context APIHook模式,我们可以创建类似Redux的存储,我们可以使用该存储来存储数据,调用分派器执行操作,从而解决了prop钻探的问题,而无需安装任何第三方状态管理系统。 瞧!

This will be a two-part article, in the first part, we are going to create a redux like store, let’s call it ‘react-store’ from now on. Then in the next part, we are going to create a simple react app, to apply that react-store practically.

这将是一个分为两部分的文章,在第一部分中,我们将创建一个类似redux的store,从现在开始我们将其称为“ react-store” 。 然后在下一部分中,我们将创建一个简单的react应用程序,以实际应用该react-store

让我们开始吧 (Let’s Get Started)

To get started we need to understand how React Context works. The best way to learn about the Context is to go through the Official Documentation. In short, Context is a way to share data across the react-app without having to pass them explicitly (remember, prop drilling). So, we will create a context, then wrap our app with it and any state we keep on the context will be available throughout the app. Seems simple enough. Actually, we will see that it is.

首先,我们需要了解React Context是如何工作的。 了解上下文的最佳方法是阅读官方文档 。 简而言之,Context是一种在整个react-app中共享数据而无需显式传递数据的方式(请记住,prop钻探)。 因此,我们将创建一个上下文,然后用它包装我们的应用程序,我们在上下文中保留的任何状态将在整个应用程序中可用。 似乎很简单。 实际上,我们会看到的。

Then comes, React Hooks. After being included in React's latest releases, the hooks have become such a buzzword, to be honest, it’s actually deserving. We are going to use useReducer hook (Wait, where have I heard the name reducer before? Yeah, right in redux), which to be honest is the more advanced version of useState hook. To know more about them go through their Documentation as usual.

然后是React Hooks 。 在被包含在React的最新版本中之后,这些钩子已经成为了一个时髦的词,说实话,这实际上是值得的。 我们将使用useReducer钩子(等等,我以前在哪里听到过reducer的名字?是的,在redux中),说实话,它是useState钩子的更高级版本。 要了解有关它们的更多信息,请照常阅读其文档

Okay, enough chit-chat. Let’s create our desired context:

好吧,闲聊。 让我们创建所需的上下文:

const StoreContext = createContext();const GlobalStore = props => {
return <StoreContext.Provider value={{}} />;
};

We have created a context called StoreContext. And in the GlobalStore function, we are using StoreContext.Provider to expose the values throughout the app. Now, let's add state to our context.:

我们创建了一个名为StoreContext的上下文。 在GlobalStore函数中,我们使用StoreContext.Provider在整个应用程序中公开值。 现在,让我们在上下文中添加状态:

const StoreContext = createContext();const GlobalStore = props => {
if (props === undefined)
throw new Error(
"Props Undefined. You probably mixed up betweenn default/named import"
);
const { load, ...rest } = props; const [state, dispatch] = useReducer(load.reducer, load.initialState); return <StoreContext.Provider value={{ state, dispatch }} {...rest} />;
};

So, we have introduced a local state for the whole context using useReducer. It returns state which have the initial state of the app that comes from prop load.initialState and dispatch that can takes actions on the state through the load.reducer. We will create a custom hook using useContext to expose the values. So, the final file GlobalStore.js will look like this:

因此,我们使用useReducer为整个上下文引入了局部状态。 它返回state ,其具有来自道具的应用程序的初始状态load.initialStatedispatch能够通过承担国家行动load.reducer 。 我们将使用useContext创建一个自定义钩子以暴露值。 因此,最终文件GlobalStore.js将如下所示:

import React, { createContext, useContext, useReducer } from "react";const StoreContext = createContext();const GlobalStore = props => {
if (props === undefined)
throw new Error(
"Props Undefined. You probably mixed up betweenn default/named import"
);
const { load, ...rest } = props; const [state, dispatch] = useReducer(load.reducer, load.initialState); return <StoreContext.Provider value={{ state, dispatch }} {...rest} />;
};export const useStore = () => useContext(StoreContext);export default GlobalStore;

We will now create a combineReducer function, just like Redux to combine multiple reducers if needed. The combineReducer.js file will look like this:

现在,我们将创建一个combineReducer函数,就像Redux一样,如果需要的话可以组合多个reducer。 combineReducer.js文件将如下所示:

const combineReducer = reducers => {
const finalReducers = {}; Object.keys(reducers).forEach(key => {
if (typeof reducers[key] === "function") finalReducers[key] = reducers[key];
else throw new Error(`${key} reducer must be a function`);
});
const finalReducerKeys = Object.keys(finalReducers); return (state, action) => {
let hasChanged = false;
const nextState = {};
finalReducerKeys.forEach(key => {
const reducer = finalReducers[key];
const previousStateForKey = state[key]; const nextStateForKey = reducer(previousStateForKey, action);
nextState[key] = nextStateForKey;
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
}); hasChanged =
hasChanged || finalReducerKeys.length !== Object.keys(state).length;
return hasChanged ? nextState : state;
};
};export default combineReducer;

We will also create a createStore.js file just to create an object out of reducer and initialState. It's so trivial.

我们还将创建一个createStore.js文件,仅用于根据reducerinitialState创建一个对象。 太琐碎了。

const createStore = (reducer, initialState) => ({ reducer, initialState });export default createStore;

TL;DR: This whole code can be found here.

TL; DR :整个代码可以在这里找到。

Well, that was easy. We have our lightweight react-store ready to be used. In the next article, we will create a simple app and try to use this global store firsthand. This will be exciting. So for now, let me quote Charles Bukowski:

好吧,那很容易。 我们已经准备好使用轻量级的react-store 。 在下一篇文章中,我们将创建一个简单的应用程序并尝试直接使用该全球商店。 这将令人兴奋。 现在,让我引用Charles Bukowski的话

If you’re going to try, go all the way. There is no other feeling like that. You will be alone with the gods, and the nights will flame with fire. You will ride life straight to perfect laughter. It’s the only good fight there is.

如果您要尝试,请继续。 没有其他感觉。 您将与众神独处,夜晚将燃烧着火焰。 您将直接生活到完美的笑声。 这是唯一的好斗争

翻译自: https://medium.com/craftsmenltd/implementing-a-global-store-using-react-context-and-hook-patterns-part-1-233368f0b2df

react 的全局存储

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值