Двойной рендеринг с настраиваемым хуком React - PullRequest
0 голосов
/ 02 августа 2020

Я пытаюсь реализовать настраиваемый перехватчик глобального состояния на основе статьи здесь Управление состоянием с помощью перехватчиков 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;
...