Я пытаюсь реализовать настраиваемый перехватчик глобального состояния на основе статьи здесь Управление состоянием с помощью перехватчиков React - без Redux или 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];
}
Если вы войдете в консоль внутри этого фрагмента кода, вы увидите, что он запускается дважды при первоначальном рендеринге, а также дважды при каждом обновлении ловушки.
Любая помощь в том, как это исправить, будет очень признательна.
Вот полный код:
CodeSandbox
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;