使用react自定义钩子进行双重渲染

时间:2020-08-02 03:20:36

标签: javascript reactjs react-hooks

我正在根据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];
}

如果您在这段代码中管理日志,则可以看到它在初始渲染时运行两次,并且在每次更新钩子时也运行两次。

在解决此问题方面的任何帮助将不胜感激。

这是完整的代码:

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;

0 个答案:

没有答案