将函数放在 useEffect 中是好习惯吗?
Is it good practice to put functions inside useEffect?
问题是:
假设我在组件中有相当广泛的逻辑。我应该将所有这些逻辑放在 useEffects
中还是应该将这些函数移到 useEffect
之外并使用 useCallback
?
我找不到关于此主题的任何同行评审方法。
下面是我的意思的一个例子:
- 函数内部
useEffect
方法
useEffect(() => {
const fun1 = () => {
/**
* 50 lines of code
*/
}
fun1()
}, [var1, var2])
useEffect(() => {
const fun2 = () => {
/**
* 50 lines of code
*/
}
fun2()
}, [var3, var4])
useEffect
方法之外的函数
const fun1 = useCallback(() => {
/**
* 50 lines of code
*/
}, [var1, var2])
const fun2 = useCallback(() => {
/**
* 50 lines of code
*/
}, [var3, var4])
useEffect(() => {
fun1()
}, [fun1])
useEffect(() => {
fun2()
}, [fun2])
让我们假设它更复杂。首选哪种方法?
Assuming I have a fairly extensive logic in the component.
您可能应该将逻辑移出组件并移至挂钩中,因为这是挂钩试图解决的主要问题之一 solve。
除此之外,您的第二种方法引入了 useCallback
的附加依赖项。你这样做有什么好处?不多。但是丢失了很多东西(更复杂加上额外的依赖)。
重构一个 closure within the effect hook 的方法有很多种。因为你没有显示你的功能代码,考虑计数器组件的常见示例:
鉴于以下效用函数在范围内...
function isSingular (n: number): boolean {
return Math.abs(n) === 1;
}
function Example (): React.ReactElement {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('');
useEffect(() => {
const updateMessage = () => {
setMessage(`You clicked ${count} time${isSingular(count) ? '' : 's'}`);
};
updateMessage();
}, [count, setMessage]);
return (
<div>
<div>{message}</div>
<button onClick={() => setCount(n => n + 1)}>Increment</button>
</div>
);
}
该组件使用两个状态变量,count
和 message
(根据 count
计算)。在效果钩子的回调中定义了一个闭包updateMessage
,它封装了count
和setMessage
。有很多方法可以重构它:
Important: No matter which method you use, if it involves the use of a dependency array, make sure the list of dependencies is correct and exhaustive.
你可以在effect hook外定义闭包,直接作为回调传递(你问的就是这个):
function Example (): React.ReactElement {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('');
const updateMessage = () => {
setMessage(`You clicked ${count} time${isSingular(count) ? '' : 's'}`);
};
useEffect(updateMessage, [count, setMessage]);
return // the same JSX...
}
<div id="root"></div><script src="https://unpkg.com/react@17.0.2/umd/react.development.js"></script><script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.development.js"></script><script src="https://unpkg.com/@babel/standalone@7.16.6/babel.min.js"></script><script>Babel.registerPreset('tsx', {presets: [[Babel.availablePresets['typescript'], {allExtensions: true, isTSX: true}]]});</script>
<script type="text/babel" data-type="module" data-presets="tsx,react">
// You'd use ESM:
// import ReactDOM from 'react-dom';
// import {default as React, useEffect, useState} from 'react';
// This snippet uses UMD:
const {useEffect, useState} = React;
function isSingular (n: number): boolean {
return Math.abs(n) === 1;
}
function Example (): React.ReactElement {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('');
const updateMessage = () => {
setMessage(`You clicked ${count} time${isSingular(count) ? '' : 's'}`);
};
useEffect(updateMessage, [count, setMessage]);
return (
<div>
<div>{message}</div>
<button onClick={() => setCount(n => n + 1)}>Increment</button>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById('root'));
</script>
您可以将其定义为 impure function 而不是闭包:
function updateMessage (
count: number,
setString: React.Dispatch<React.SetStateAction<string>>,
): void {
setString(`You clicked ${count} time${isSingular(count) ? '' : 's'}`);
};
function Example (): React.ReactElement {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('');
useEffect(() => updateMessage(count, setMessage), [count, setMessage]);
return // the same JSX...
}
您可以将与 message
状态相关的所有内容提取到 custom hook:
function useMessage (count: number): string {
return `You clicked ${count} time${isSingular(count) ? '' : 's'}`;
};
function Example (): React.ReactElement {
const [count, setCount] = useState(0);
const message = useMessage(count);
return // the same JSX...
}
您可以使用 memo hook:
function Example (): React.ReactElement {
const [count, setCount] = useState(0);
const message = useMemo(() => `You clicked ${count} time${isSingular(count) ? '' : 's'}`, [count]);
return // the same JSX...
}
希望这能给您一些观点,然后您可以将其应用于您的组件代码。
问题是:
假设我在组件中有相当广泛的逻辑。我应该将所有这些逻辑放在 useEffects
中还是应该将这些函数移到 useEffect
之外并使用 useCallback
?
我找不到关于此主题的任何同行评审方法。
下面是我的意思的一个例子:
- 函数内部
useEffect
方法
useEffect(() => {
const fun1 = () => {
/**
* 50 lines of code
*/
}
fun1()
}, [var1, var2])
useEffect(() => {
const fun2 = () => {
/**
* 50 lines of code
*/
}
fun2()
}, [var3, var4])
useEffect
方法之外的函数
const fun1 = useCallback(() => {
/**
* 50 lines of code
*/
}, [var1, var2])
const fun2 = useCallback(() => {
/**
* 50 lines of code
*/
}, [var3, var4])
useEffect(() => {
fun1()
}, [fun1])
useEffect(() => {
fun2()
}, [fun2])
让我们假设它更复杂。首选哪种方法?
Assuming I have a fairly extensive logic in the component.
您可能应该将逻辑移出组件并移至挂钩中,因为这是挂钩试图解决的主要问题之一 solve。
除此之外,您的第二种方法引入了 useCallback
的附加依赖项。你这样做有什么好处?不多。但是丢失了很多东西(更复杂加上额外的依赖)。
重构一个 closure within the effect hook 的方法有很多种。因为你没有显示你的功能代码,考虑计数器组件的常见示例:
鉴于以下效用函数在范围内...
function isSingular (n: number): boolean {
return Math.abs(n) === 1;
}
function Example (): React.ReactElement {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('');
useEffect(() => {
const updateMessage = () => {
setMessage(`You clicked ${count} time${isSingular(count) ? '' : 's'}`);
};
updateMessage();
}, [count, setMessage]);
return (
<div>
<div>{message}</div>
<button onClick={() => setCount(n => n + 1)}>Increment</button>
</div>
);
}
该组件使用两个状态变量,count
和 message
(根据 count
计算)。在效果钩子的回调中定义了一个闭包updateMessage
,它封装了count
和setMessage
。有很多方法可以重构它:
Important: No matter which method you use, if it involves the use of a dependency array, make sure the list of dependencies is correct and exhaustive.
你可以在effect hook外定义闭包,直接作为回调传递(你问的就是这个):
function Example (): React.ReactElement {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('');
const updateMessage = () => {
setMessage(`You clicked ${count} time${isSingular(count) ? '' : 's'}`);
};
useEffect(updateMessage, [count, setMessage]);
return // the same JSX...
}
<div id="root"></div><script src="https://unpkg.com/react@17.0.2/umd/react.development.js"></script><script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.development.js"></script><script src="https://unpkg.com/@babel/standalone@7.16.6/babel.min.js"></script><script>Babel.registerPreset('tsx', {presets: [[Babel.availablePresets['typescript'], {allExtensions: true, isTSX: true}]]});</script>
<script type="text/babel" data-type="module" data-presets="tsx,react">
// You'd use ESM:
// import ReactDOM from 'react-dom';
// import {default as React, useEffect, useState} from 'react';
// This snippet uses UMD:
const {useEffect, useState} = React;
function isSingular (n: number): boolean {
return Math.abs(n) === 1;
}
function Example (): React.ReactElement {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('');
const updateMessage = () => {
setMessage(`You clicked ${count} time${isSingular(count) ? '' : 's'}`);
};
useEffect(updateMessage, [count, setMessage]);
return (
<div>
<div>{message}</div>
<button onClick={() => setCount(n => n + 1)}>Increment</button>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById('root'));
</script>
您可以将其定义为 impure function 而不是闭包:
function updateMessage (
count: number,
setString: React.Dispatch<React.SetStateAction<string>>,
): void {
setString(`You clicked ${count} time${isSingular(count) ? '' : 's'}`);
};
function Example (): React.ReactElement {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('');
useEffect(() => updateMessage(count, setMessage), [count, setMessage]);
return // the same JSX...
}
您可以将与 message
状态相关的所有内容提取到 custom hook:
function useMessage (count: number): string {
return `You clicked ${count} time${isSingular(count) ? '' : 's'}`;
};
function Example (): React.ReactElement {
const [count, setCount] = useState(0);
const message = useMessage(count);
return // the same JSX...
}
您可以使用 memo hook:
function Example (): React.ReactElement {
const [count, setCount] = useState(0);
const message = useMemo(() => `You clicked ${count} time${isSingular(count) ? '' : 's'}`, [count]);
return // the same JSX...
}
希望这能给您一些观点,然后您可以将其应用于您的组件代码。