具有常量输入参数的反应钩子 - 钩子创建者?
React hook with constant input parameter - hook creator?
由于 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 (
...
)
}
你是如何解决这种情况的?
一种方法是使用 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
以确保它始终只是初始值。
另一种解决方案是 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 };
};
由于 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 (
...
)
}
你是如何解决这种情况的?
一种方法是使用 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
以确保它始终只是初始值。
另一种解决方案是 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 };
};