我有一个子组件,它在useEffect中执行fetch,然后调用传入的onChange处理程序.子组件被重新呈现3次(并执行fetch 3次),所有这些都是因为父组件的onChange函数"更改"了.

要求父母将onChange包装在useCallback中是可行的,但似乎是错误的,因为父母不应该关心子元素是如何实现的.我还可以让子元素缓存onChange(可能有useRef或像usePrevious这样的定制钩子),并判断useEffect是否发生了更改,但这似乎也有点过头了.

对于这种模式,有没有最佳实践?(理想情况下不需要重做或类似的)

import { useEffect, useState } from 'react';

const Child = ({ onChange, value }) => {
  useEffect(() => {
    console.log("called");
    fetch(`blah/${value}`)
      .then((result) => onChange(result))
      .catch((error) => onChange(error));
  }, [value, onChange]);

  return <div>Child</div>;
};

export default function Parent () {
  const [result, setResult] = useState();

  return (
    <div>
      {result}
      <Child 
        value={0}
        onChange={r => {
          setResult(r.toString());
        }} 
      />
    </div>
  );
}

codesandbox

推荐答案

要求家长将onChange包在useCallback中是可行的,但 似乎是错误的,因为父母不应该关心子元素如何 已经实施了.

这不是关于父组件caring,而是关于子组件100如何传递props 或其任何实现,而是为消费者提供稳定的引用,并且不会触发不必要的重新呈现.换句话说,这是一种性能提升.

Reaction组件重新渲染的原因有两个,它们的状态或props 更新(e.g. via new references),或者父组件重新渲染.

您正在传递一个匿名回调函数作为onChangeprops ,所以每当这个父组件呈现时,它都会提供一个新的onChange函数引用,并且肯定会触发子重新呈现.

对于这种模式,有没有最佳实践?

是的,记住传递下来的回调,以便将其作为稳定的引用提供.

记忆onChange处理程序函数,以便对子组件提供稳定的函数引用,以便仅在valueprops 更新时呈现to the DOM.

import { useCallback, useEffect, useState } from 'react';

export default function Parent () {
  const [result, setResult] = useState();

  const onChangeHandler = useCallback(r => {
    setResult(r.toString());
  }, [setResult]);

  return (
    <div>
      {result}
      <Child 
        value={0}
        onChange={onChangeHandler} 
      />
    </div>
  );
}

const Child = ({ onChange, value }) => {
  useEffect(() => {
    console.log("called");
    fetch(`blah/${value}`)
      .then(onChange)
      .catch(onChange);
  }, [value, onChange]);

  return <div>Child</div>;
};

因此,现在Reaction可以告诉我们,onChange引用不会将Render更改为Render,并且只要valueprops 没有更新,Reaction就可以放弃子组件(and its 102 sub-ReactTree)重新渲染even though重新渲染的父组件.同样,这只是一个性能优化,以减少不必要的重新渲染.

有关记忆函数引用的更多详细信息和其他原因,请参阅useCallback hook documentation.

Reactjs相关问答推荐

构建next.js项目时状态不变,但在dev服务器中

NextJS(AppRouter)、Apollo(客户端),在根布局中使用ApolloProvider时出错

Reaction路由的问题-在Effect使用API调用响应设置状态之前呈现页面

Redux Provider Stuck甚至彻底遵循了文档

有没有办法在Shopify中显示自定义计算的交货日期?

在数组对象内的数组上进行映射

在transformResponse中使用来自其他查询的缓存

使用自动播放的视频组件呈现登录页面时出现JEST测试错误

Reaction路由-如何在布局路由内呈现&q;/:id&q;路由

状态更改是否卸载功能组件

Github 操作失败:发布 NPM 包

定位数组中的一项(React、useState)

更新对象状态的父数组时记住子组件

我无法通过 useContext 显示值

Primereact 的日历组件在每个月 12 日之后使用非唯一键生成

Redux,状态未定义

如何使用react 路由将 url 参数限制为一组特定的值?

加密 Django Rest Framework API 响应 + 解密响应应用程序中的响应

多次响应获取发送请求

链接的音译 Gatsby JS