简体   繁体   English

我可以在传递给 useCallback 的函数内部设置状态吗?

[英]Can I setState inside function passed to useCallback?

This question occurred to me because as we know from the docs:我想到了这个问题,因为正如我们从文档中知道的那样:

useCallback(fn, deps) is equivalent to useMemo(() => fn, deps). useCallback(fn, deps) 等价于 useMemo(() => fn, deps)。

The docs of useMemo say: useMemo的文档说:

Remember that the function passed to useMemo runs during rendering.请记住,传递给 useMemo 的函数在渲染期间运行。 Don't do anything there that you wouldn't normally do while rendering .不要在那里做任何你在渲染时通常不会做的事情 For example, side effects belong in useEffect, not useMemo.比如副作用属于useEffect,而不是useMemo。

I assume that also implies I can't do setState .我认为这也意味着我不能做setState

Now, if we have this code:现在,如果我们有这个代码:

const memoizedValue = useMemo(() => computeExpensiveValue(), []);

Does above quote mean we can't do a side effect inside computeExpensiveValue or the inline function which was the argument to useMemo ?上面的引用是否意味着我们不能在computeExpensiveValue或作为useMemo参数的内联函数中产生useMemo

Because if it means we can't do side effect inside computeExpensiveValue it means we can't do a side effect also in a function passed to useCallback because that line is same as:因为如果这意味着我们不能在computeExpensiveValue产生computeExpensiveValue则意味着我们也不能在传递给useCallback的函数中产生useCallback因为该行与以下内容相同:

const memoizedValue = useCallback(computeExpensiveValue, []);

I see how you got there, but it's a slight misreading of the docs.我明白你是如何到达那里的,但这是对文档的轻微误读。 (Fairly easy mistake to make.) (相当容易犯的错误。)

The function that the useMemo docs are talking about isn't your function ( fn ), it's this function in the useCallback "equivalent useMemo " example: useMemo文档所谈论的函数不是您的函数( fn ),而是useCallback “等效useMemo ”示例中的此函数:

useMemo(() => fn, deps).
//      ^^^^^^^^

That function doesn't call any state setters, so it's fine.该函数不调用任何状态设置器,所以没问题。

It's absolutely fine and completely normal to call state setters in callback functions you memoize via useCallack .在您通过useCallack回调函数中调用状态设置器是绝对正常且完全正常的。 (As long as you don't call your callback during rendering.) When you do, be sure to either: (只要您在渲染期间不调用回调。)执行此操作时,请确保:

  • Not use any state variables in when calling the state setter:调用状态设置器时不使用任何状态变量:
     const fn = useCallback(() => { setSomething(someValueNotFromState); }, []);
    or或者
  • Use the callback form of the state setter:使用状态设置器的回调形式:
     const fn = useCallback(() => { setSomething(something => something + 1); }, []);
    or或者
  • Declare any state members you're going to use in the callback as dependencies:将您将在回调中使用的任何状态成员声明为依赖项:
     const fn = useCallback(() => { setSomething(something + 1); // I usually avoid this }, [something]); // ^^^^^^^^^

A more verbose example/comparison:一个更详细的例子/比较:

const [value, setValue] = useState(0);

const changeHandler1 = useCallback((event) => {
    // Absolutely fine to call `setValue` here
    setValue(event.currentTarget.value);
}, []);

// equivalent to:

const changeHandler2 = useMemo(() => {
    // NOT okay to call `setValue` here (the function we pass to `useMemo`)

    return (event) => {
        // Absolutely fine to call `setValue` here
        setValue(event.currentTarget.value);
    };
}, []);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM