我对useEffect挂钩略知一二,但我认为还有更多的知识需要掌握.其中一些内容不在文档中.拜托,任何贡献都会对你们有很大帮助.
我的一些问题包括:
-
就像在开发中一样,在产品中也会在初始渲染时调用useEffect吗?
-
如果是这样,我们如何以最好的方式控制这一点?
-
我们如何在这个钩子上使用清理功能?
-
如何在useEffect中进行异步调用?
我在Use Effect上的try 通常会让我感觉自己是一个糟糕的开发者
我对useEffect挂钩略知一二,但我认为还有更多的知识需要掌握.其中一些内容不在文档中.拜托,任何贡献都会对你们有很大帮助.
我的一些问题包括:
就像在开发中一样,在产品中也会在初始渲染时调用useEffect吗?
如果是这样,我们如何以最好的方式控制这一点?
我们如何在这个钩子上使用清理功能?
如何在useEffect中进行异步调用?
我在Use Effect上的try 通常会让我感觉自己是一个糟糕的开发者
请看一下react docs和react beta docs.
当启用严格模式时,Reaction将在第一次实际设置之前运行一个额外的仅限开发的设置+清理周期.这是一个压力测试,可确保您的清理逻辑"反映"您的设置逻辑,并确保它停止或undo撤消设置正在执行的任何操作.如果这会导致问题,则需要实现Cleanup函数.
我真的不知道你说的以最好的方式控制它是什么意思.无论何时挂载组件,您的效果或设置代码都会运行.也许吧 How to handle the Effect firing twice in development? 美元可以帮到你.您有时可能想要防止在组件挂载时执行该效果,您可以使用ref跳过该效果.见this stackoverflow question
您在useEffect
中返回的函数会为您进行清理.See.例如,如果您在useEffect
中添加了一个事件侦听器,则在您在其内部返回的函数中删除了该侦听器.见this link
useEffect(() => {
const listener = () => { /* Do something */ };
window.addEventListener("click", listener);
return () => {
window.removeEventListener("click", listener);
};
}, []);
useEffect(() => {
async function asyncFunction() {
/* Do something */
}
asyncFunction();
}, []);
Update:
看看You Might Not Need an Effect 个.它解释了一些你可能根本不需要效果的情况.
移除不必要的效果将使您的代码更易于遵循、运行更快,并且不容易出错.
Update 2:
You can probably skip this part for now, but it might help you to have a better grasp of 100, event handlers and what to expect in the future.
Separating Events from Effects试图解释效果和事件处理程序之间的区别,为什么区分这两者并在效果中使用事件处理程序很重要.
只有当您再次执行相同的交互时,事件处理程序才会重新运行.与事件处理程序不同,如果它们读取的某些值(如props 或状态变量)不同于上次渲染期间的值,则效果将重新同步.有时,您还需要这两种行为的混合:一种响应某些值而不是另一些值而重新运行的效果.这一页将教你如何做到这一点.
有时,您可能会使用可以访问props 或效果内部状态的事件处理程序.但您不希望在事件处理程序中使用的值每次更改时都触发useEffect
.下面的例子取自useEffect shouldn’t re-fire when event handlers change
.
function Chat({ selectedRoom }) {
const [muted, setMuted] = useState(false);
const theme = useContext(ThemeContext);
useEffect(() => {
const socket = createSocket('/chat/' + selectedRoom);
socket.on('connected', async () => {
await checkConnection(selectedRoom);
showToast(theme, 'Connected to ' + selectedRoom);
});
socket.on('message', (message) => {
showToast(theme, 'New message: ' + message);
if (!muted) {
playSound();
}
});
socket.connect();
return () => socket.dispose();
}, [selectedRoom, theme, muted]); // ???? Re-runs when any of them change
// ...
}
如您所见,您不希望每次更改theme
或muted
个变量时都重新连接.只有当selectedRoom
值更改时,您才希望运行效果(连接和断开与服务器的连接).
因此,Reaction团队提出了RFC: useEvent的建议,它提供了
用于定义具有始终稳定的函数标识的事件处理程序的钩子.
useEvent
是一个实验性和不稳定的API,还没有添加到Reaction(稳定版本)YE中,所以你还不能使用它.
这可能是离题的,但可能会帮助您更好地理解Reaction及其生命周期:GitHub上有这个问题useCallback() invalidates too often in practice issue.一个workaround是创建一个定制钩子,该钩子返回一个函数,该函数的标识是稳定的,并且在重新呈现时不会更改:
function useEventCallback(fn) {
let ref = useRef();
useLayoutEffect(() => {
ref.current = fn;
});
return useCallback(() => (0, ref.current)(), []);
}
或者你可以使用use-event-callback的套餐.
请注意,useEventCallback
并不能精确地模仿useEvent
:
用于useEvent的高保真填充是不可能的,因为在Reaction中没有生命周期或钩子可以用来在正确的时间切换
.current
.虽然在很多情况下,use-event-callback"足够接近",但它不会在渲染过程中抛出,而且时机也不太合适.在出现包含内置useEvent
实现的Reaction版本之前,我们不建议广泛采用此模式.