Реагировать хуком с постоянным входным параметром - создатель хука - PullRequest
1 голос
/ 09 мая 2019

Поскольку перехватчики React зависят от порядка выполнения, обычно не следует использовать перехватчики внутри циклов. Я столкнулся с парой ситуаций, когда у меня есть постоянный ввод в ловушку, и поэтому не должно быть никаких проблем. Единственное, что меня интересует, это как заставить входные данные быть постоянными.

Ниже приведен упрощенный пример:

const useHookWithConstantInput = (constantIdArray) => {
  const initialState = buildInitialState(constantIdArray);
  const [state, changeState] = useState(initialState);

  const callbacks = constantIdArray.map((id) => useCallback(() => {
    const newState = buildNewState(id, constantIdArray);
    changeState(newState);
  }));

  return { state, callbacks };
}
const idArray = ['id-1', 'id-2', 'id-3'];

const SomeComponent = () => {
  const { state, callbacks } = useHookWithConstantInput(idArray);

  return (
    <div>
      <div onClick={callbacks[0]}>
        {state[0]}
      </div>

      <div onClick={callbacks[1]}>
        {state[1]}
      </div>

      <div onClick={callbacks[2]}>
        {state[2]}
      </div>
    </div>
  )
}

Существует ли шаблон, как заставить constantIdArray не изменяться? Моя идея состоит в том, чтобы использовать функцию создателя для ловушки, как это:

const createUseHookWithConstantInput = (constantIdArray) => () => {
  ...
}

const idArray = ['id-1', 'id-2', 'id-3'];

const useHookWithConstantInput = createUseHookWithConstantInput(idArray)

const SomeComponent = () => {
  const { state, callbacks } = useHookWithConstantInput();

  return (
    ...
  )
}

Как вы решаете подобные ситуации?

Ответы [ 2 ]

1 голос
/ 09 мая 2019

Один из способов сделать это - использовать useEffect с пустым списком зависимостей, чтобы он запускался только один раз.Внутри этого вы можете установить ваши обратные вызовы, и после этого они никогда не изменятся, потому что useEffect не будет работать снова.Это выглядело бы следующим образом:

const useHookWithConstantInput = (constantIdArray) => {
  const [state, changeState] = useState({});
  const [callbacks, setCallbacks] = useState([]);

  useEffect(() => {
    changeState(buildInitialState(constantIdArray));
    const callbacksArray = constantIdArray.map((id) => {
        const newState = buildNewState(id, constantIdArray);
        changeState(newState);
    });

    setCallbacks(callbacksArray);
  }, []);

  return { state, callbacks };
}

Хотя это установит два состояния при первом запуске вместо предоставления им начальных значений, я бы сказал, что это лучше, чем создание состояния и создание новых обратных вызовов каждый раз, когда перехватываетсявыполняется.

Если вам не нравится этот маршрут, вы могли бы просто создать состояние, подобное const [constArray, setConstArray] = useState(constantIdArray);, и поскольку параметр, заданный useState, используется только в качестве значения по умолчанию, он будетникогда не меняются, даже если constantIdArray меняется.Тогда вам просто нужно будет использовать constArray в остальной части ловушки, чтобы убедиться, что оно всегда будет только начальным значением.

0 голосов
/ 13 мая 2019

Другое решение, к которому можно обратиться, - useMemo.Это то, что я в итоге реализовал.

const createCallback = (id, changeState) => () => {
  const newState = buildNewState(id, constantIdArray);
  changeState(newState);
};

const useHookWithConstantInput = (constantIdArray) => {
  const initialState = buildInitialState(constantIdArray);
  const [state, changeState] = useState(initialState);

  const callbacks = useMemo(() =>
    constantIdArray.map((id) => createCallback(id, changeState)),
    [],
  );

  return { state, callbacks };
};
...