我正在根据State Management with React Hooks — No Redux or Context API上的文章来实现自定义全局状态钩子。我不断得到双重渲染。似乎包含以下代码:
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];
}
如果您在这段代码中管理日志,则可以看到它在初始渲染时运行两次,并且在每次更新钩子时也运行两次。
在解决此问题方面的任何帮助将不胜感激。
这是完整的代码:
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 = false;
const useValue = useGlobalState(initialState);
export default useValue;
和组件
import React from 'react';
import useValue from '../store/useValue';
const Component1 = () => {
const [value, setValue] = useValue();
console.log('rendered component');
return (
<div>
<p>Value1: {value ? 'true' : 'false'}</p>
<button onClick={() => setValue(!value)}>Toggle Me</button>
</div>
);
};
export default Component1;