首页 > 解决方案 > React 无法对未安装的组件执行状态更新

问题描述

我正在使用以下方法从其他组件控制我的标题。但是,我在更改页面时遇到了旧的“无法对未安装的组件执行反应状态更新”错误

export const store = {
    state: {},
    setState(value) {
        this.state = value;
        this.setters.forEach(setter => setter(this.state));
    },
    setters: []
};
store.setState = store.setState.bind(store);

export function useStore() {
    const [ state, set ] = useState(store.state);
    if (!store.setters.includes(set)) {
        store.setters.push(set);
    }

    return [ state, store.setState ];
}

然后我的标题使用它来设置一个类并控制它是需要在白色上显示黑色还是在黑色上显示白色

const Header = () => {
    const [type] = useStore();
    render( ... do stuff )
};

我在页面上的组件导入 useStore 然后根据多种因素调用 setType,某些布局是一种类型,有些是其他类型,有些因 API 调用而异,因此有很多不同的组件需要调用该函数来设置标题状态。

const Flexible = (props) => {
    const [type, setType] = useStore();
    if( type !== 'dark ){ setType('dark') }
    ... do stuff
};

其自身的标头始终在页面上,位于路由器之前和外部,并且永远不会卸载。

这一切都很好,并设置了标题。但是,当我使用 React Router 更改页面时,出现无法设置状态错误。我不明白为什么会收到此错误。我首先认为组件可能会尝试使用 react 路由器再次运行,因此我将代码移动以将标头状态设置为仅在初始化时运行但没有帮助的 useEffect。

标签: javascriptreactjsstatestore

解决方案


您只会添加到设置器中,永远不会删除。因此,当组件卸载时,它将保留在设置器中,并且下次应用程序的其他部分尝试设置状态时,所有设置器都会被调用,包括卸载组件的设置器。这会导致您看到的错误。

您需要修改自定义挂钩以使用 useEffect,以便在卸载时可以使用拆卸逻辑。像这样的东西:

export function useStore() {
  const [ state, set ] = useState(store.state);
  useEffect(() => {
    store.setters.push(set);
    return () => {
      const i = store.setters.indexOf(set);
      if (i > -1) {
        store.setters.splice(i, 1);
      }
    }      
  }, []);

  return [ state, store.setState ];
}

推荐阅读