【发布时间】:2021-05-24 18:59:35
【问题描述】:
需要在 React 组件或自定义 React 钩子中调用 React 钩子。它不能在循环内使用。考虑到这一点,请考虑以下情况:
const useListenToStateChange = (state, onEvent, key) => {
const value = state[key];
useEffect(() => {
if (value === null) {
onEvent(null);
} else {
onEvent(key, value);
}
}, [value]);
};
const ExampleComponent = (props) => {
const { context, onError } = props;
const { state } = useContext(context);
useListenToStateChange(state, onError, KEY_ARRAY[0]);
useListenToStateChange(state, onError, KEY_ARRAY[1]);
useListenToStateChange(state, onError, KEY_ARRAY[2]);
useListenToStateChange(state, onError, KEY_ARRAY[3]);
useListenToStateChange(state, onError, KEY_ARRAY[4]);
useListenToStateChange(state, onError, KEY_ARRAY[5]);
useListenToStateChange(state, onError, KEY_ARRAY[6]);
useListenToStateChange(state, onError, KEY_ARRAY[7]);
useListenToStateChange(state, onError, KEY_ARRAY[8]);
useListenToStateChange(state, onError, KEY_ARRAY[9]);
return <Text>{getTitle(state)}</Text>;
};
ExampleComponent 的返回值并不是重点,所以请忽略它。我担心的是useListenToStateChange被复制粘贴了十次,显然违反了DRY原则。
假设我们需要以这种方式调用useListenToStateChange——我们需要一个监听器来监听useContext返回的state对象的值,它会在发生变化时执行一个带有副作用的函数(即,回调不能在更新state的reducer内部调用;我们需要调用useEffect)。
这就是柯里化的用武之地(注意:我使用lodash/fp 中的curry 和map):
const useListenToStateChange = _.curry((state, onEvent, key) => {
const value = state[key];
useEffect(() => {
if (value === null) {
onEvent(null);
} else {
onEvent(key, value);
}
}, [value]);
});
const ExampleComponent = (props) => {
const { context, onError } = props;
const { state } = useContext(context);
const listenToState = useListenToStateChange(state, onError);
_.map(listenToState, KEY_ARRAY);
return <Text>{getTitle(state)}</Text>;
};
以上代码在 React Native 中有效,运行不报错。
我喜欢它的读取方式,并且我喜欢这种方法使我们能够避免复制粘贴所有键。想象一下,如果您需要基于 KEY_ARRAY 数组设置多个侦听器。那将是一场噩梦。乍一看,我们也是这样遵循钩子规则的:useListenToStateChange 是一个返回 JavaScript 函数的钩子,我们在 React 组件中调用该钩子。
但我正在思考的“问题”是,当你对一个函数进行 curry 时,显然它还没有执行。您必须提供最后一个参数才能运行。这意味着listenToState 在技术上是一个 React 钩子:当你调用它时,它将执行 useListenToStateChange 内部的 useEffect 钩子。
但是,它的名称不像钩子,因此绕过了 React 中的检查,即您必须在顶层调用它。这意味着您可以映射KEY_ARRAY,并且由于它是一个预定义的非动态数组,因此可以保证在每次渲染时都以相同的顺序调用挂钩。因此,它避免了React docs 中列出的问题。
所以我的问题是:这种使用柯里化 React 钩子的做法是否违反了钩子的规则?换句话说,这种模式是好的做法吗?
【问题讨论】:
标签: reactjs react-native react-hooks standards currying