【问题标题】:Can I setState inside function passed to useCallback?我可以将 setState 内部函数传递给 useCallback 吗?
【发布时间】:2021-11-04 13:03:44
【问题描述】:

我之所以想到这个问题,是因为我们从文档中了解到:

useCallback(fn, deps) 等价于 useMemo(() => fn, deps)。

useMemo 的文档说:

请记住,传递给 useMemo 的函数在渲染期间运行。 不要在那里做任何你在渲染时通常不会做的事情。 比如副作用属于useEffect,而不是useMemo。

我认为这也意味着我不能做setState

现在,如果我们有这段代码:

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

以上引用是否意味着我们不能在 computeExpensiveValue 或作为 useMemo 参数的内联函数中产生副作用?

因为如果这意味着我们不能在 computeExpensiveValue 中产生副作用,这意味着我们也不能在传递给 useCallback 的函数中产生副作用,因为该行与以下内容相同:

const memoizedValue = useCallback(computeExpensiveValue, []);

【问题讨论】:

  • 我怀疑你不是唯一一个被文档的那部分混淆的人。

标签: javascript reactjs react-hooks


【解决方案1】:

我知道您是如何到达那里的,但这是对文档的轻微误读。 (相当容易犯的错误。)

useMemo 文档所说的函数不是您的函数 (fn),而是 useCallback“等效 useMemo”示例中的函数:

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

该函数不调用任何状态设置器,所以没问题。

在您通过useCallack 记忆的回调函数中调用状态设置器是完全正常且完全正常的。 (只要您在渲染期间不调用回调。) 当您这样做时,请务必:

  • 在调用状态设置器时不使用任何状态变量:
    const fn = useCallback(() => {
         setSomething(someValueNotFromState);
    }, []);
    
  • 使用状态设置器的回调形式:
    const fn = useCallback(() => {
         setSomething(something => something + 1);
    }, []);
    
  • 将要在回调中使用的任何状态成员声明为依赖项:
    const fn = useCallback(() => {
         setSomething(something + 1); // I usually avoid this
    }, [something]);
    //  ^^^^^^^^^
    

更详细的示例/比较:

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);
    };
}, []);

【讨论】:

  • 我不确定您对“将回调与您将与状态设置器一起使用的任何状态成员一起记忆”的意思?您的意思是传递正确的依赖项?
  • @giorgimoniava "所以文档指的是 "() => computeExpensiveValue()"?" 是的,完全正确! “您的意思是传递正确的依赖项?” 是的。这将是一种不那么令人困惑的方式。 :-D 我已经对其进行了编辑,并为清楚起见给出了所有这三件事的示例。
猜你喜欢
  • 2017-09-04
  • 1970-01-01
  • 2018-05-22
  • 1970-01-01
  • 2019-09-24
  • 1970-01-01
  • 1970-01-01
  • 2016-03-13
  • 2014-02-15
相关资源
最近更新 更多