我最近看到了下面的文章State Management with React Hooks — No Redux or Context API。自从开始React以来,谈论最多的问题总是状态管理和全局状态。Redux一直是流行的选择,最近是上下文API。但这种方法似乎更容易,代码更少,可伸缩性更强。
我的问题是,是否有人能看到使用这种我可能忽略了的状态管理方法的缺点,我对代码做了一些修改以支持SSR,它可以在Nextjs中工作,并且使其在使用操作和状态变量设置方面更加友好。
useGlobalState.js
import React, { useState, useEffect, useLayoutEffect } from 'react';
const effect = typeof window === 'undefined' ? useEffect : useLayoutEffect;
function setState(newState) {
if (newState === this.state) return;
this.state = newState;
this.listeners.forEach((listener) => {
listener(this.state);
});
}
function useCustom() {
const newListener = useState()[1];
effect(() => {
this.listeners.push(newListener);
return () => {
this.listeners = this.listeners.filter((listener) => listener !== newListener);
};
}, []);
return [this.state, this.setState, this.actions];
}
function associateActions(store, actions) {
const associatedActions = {};
if (actions) {
Object.keys(actions).forEach((key) => {
if (typeof actions[key] === 'function') {
associatedActions[key] = actions[key].bind(null, store);
}
if (typeof actions[key] === 'object') {
associatedActions[key] = associateActions(store, actions[key]);
}
});
}
return associatedActions;
}
const useGlobalHook = (initialState, actions) => {
const store = { state: initialState, listeners: [] };
store.setState = setState.bind(store);
store.actions = associateActions(store, actions);
return useCustom.bind(store, React);
};
export default useGlobalHook;
然后为一个状态变量设置一个自定义钩子,可以是一个简单的字符串或者是一个对象下面是一个简单的例子:
import useGlobalState from './useGlobalState';
const initialState = 'Hi';
// Example action for complex processes setState will be passed to component for use as well
const someAction = (store, val) => store.setState(val);
const useValue = useGlobalState(initialState, { someAction });
export default useValue;
以及在组件中的使用:
import React from 'react'
import useVal from './useVal'
export default () => {
const [val, setVal, actions] = useVal();
const handleClick = () => {
setVal('New Val');
// or use some actions
actions.someAction('New Val');
}
return(
<div>{val}</div>
<button onClick={handleClick}>Click Me</button>
)
}
这看起来是一种更干净、更简单的方法,我想知道为什么这不是状态管理的最佳方法。首先,你不必将所有东西都 Package 在一个提供程序中。其次,它非常容易实现,实际应用中涉及的代码也少得多。有人能看到使用这种方法的缺点吗?我唯一能想到的是上下文API的重新呈现问题,但在小块中,这不应该是一个问题。
2条答案
按热度按时间t8e9dugd1#
我一直在使用一种类似的方法,我真的很喜欢它。我真的不能相信更多的人不谈论这种方法。我在这里写了一个自定义钩子React Global Store Hook。它让你自由地从应用程序的任何地方调度和浅比较,以避免不必要的重新渲染。我不认为任何性能问题,只要你可以避免不必要的重新渲染。
总的来说,这是一个简单的概念。你基本上创建一个函数来存储你的状态,并返回2个函数。一个是设置存储状态的函数,另一个是react组件中使用的钩子。在钩子中,你使用createEffect获取react on initialrender的setState函数,并将其存储在一个数组中。然后,你可以使用这个setState函数来重新呈现你的组件。所以当你调用dispatch函数时你可以循环访问这些setState函数并调用它们。
简单举例:
然后创建一个存储并在组件中使用
然后,如果你想要一个复杂的商店对象,并且你想避免重新呈现,你可以在dispatch函数中做一个浅层比较来比较商店和新商店,类似于redux所做的。
然后在调度中,你可以在forEach循环中触发监听器之前检查它。
它比redux的样板文件少很多,而且看起来更简洁。最棒的是,它允许你将操作与函数分离,而无需将操作附加到任何东西。你可以简单地在应用中的任何地方创建一个商店,并导出
useStore
和dispatch
函数。然后,你可以从应用中的任何地方进行调度。nhhxz33t2#
很好的方法,但我仍然认为
redux
更适合大型应用程序,尤其是在性能方面。使用您的方法的一个示例是,将按钮作为单独的组件添加,同时用React.memo
Package 它,并从按钮组件触发actions.toggle()
,但按钮重新呈现2次,它不依赖于更改后的状态。所以在构建大型应用程序时,你总是在通过删除不必要的重新渲染来寻找性能提升,但这里不是这样的。
这是我的分析,谢谢你的工作。
这里是代码showcase