使用恒定输入参数来反应挂钩-挂钩创建者?

时间:2019-05-09 07:36:10

标签: reactjs react-hooks

由于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 个答案:

答案 0 :(得分:1)

执行此操作的一种方法是将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即可确保它始终仅是初始值。

答案 1 :(得分:0)

另一个可行的解决方案是使用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 };
};