我对useEffect挂钩略知一二,但我认为还有更多的知识需要掌握.其中一些内容不在文档中.拜托,任何贡献都会对你们有很大帮助.

我的一些问题包括:

  1. 就像在开发中一样,在产品中也会在初始渲染时调用useEffect吗?

  2. 如果是这样,我们如何以最好的方式控制这一点?

  3. 我们如何在这个钩子上使用清理功能?

  4. 如何在useEffect中进行异步调用?

我在Use Effect上的try 通常会让我感觉自己是一个糟糕的开发者

推荐答案

请看一下react docsreact beta docs.

  1. 无论环境如何,它始终在组件装载时运行,在第一次渲染之后运行.在开发模式中,当严格模式处于打开状态时,它会运行两次:

当启用严格模式时,Reaction将在第一次实际设置之前运行一个额外的仅限开发的设置+清理周期.这是一个压力测试,可确保您的清理逻辑"反映"您的设置逻辑,并确保它停止或undo撤消设置正在执行的任何操作.如果这会导致问题,则需要实现Cleanup函数.

  1. 我真的不知道你说的以最好的方式控制它是什么意思.无论何时挂载组件,您的效果或设置代码都会运行.也许吧 How to handle the Effect firing twice in development? 美元可以帮到你.您有时可能想要防止在组件挂载时执行该效果,您可以使用ref跳过该效果.见this stackoverflow question

  2. 您在useEffect中返回的函数会为您进行清理.See.例如,如果您在useEffect中添加了一个事件侦听器,则在您在其内部返回的函数中删除了该侦听器.见this link

  useEffect(() => {
    const listener = () => { /* Do something */ };

    window.addEventListener("click", listener);

    return () => {
      window.removeEventListener("click", listener);
    };
  }, []);
  1. 是的你可以.见this stackoverflow questionfetching data in docs
  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
  // ...
}

如您所见,您不希望每次更改thememuted个变量时都重新连接.只有当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版本之前,我们不建议广泛采用此模式.

Reactjs相关问答推荐

如何使用json将购物车数组传递到后台API

通过单击具有此值的按钮将值添加到数组对象键

如何访问子集合中的文档?

for each 子级加载父路由加载器

如何删除 bootstrap 手风琴上的边框

tRPC/react-query,在所有查询完成之前,组件不会收到任何 useQuery 的结果

MERN,将动态列表中的元素插入数组

Mui DataGrid 在第二页和前一页上显示项目时出现问题

数据表格组件需要所有行都具有唯一的ID属性.或者,您可以使用getRowId属性.

从ReactDataGridtry 将数据传递给父组件

如何使用 redux 和 react-plotly.js

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

在复选框中react 检索选中的值

如何通过 React JS 中的映射将新元素添加到对象数据数组中

如果传递给挂钩的数据需要事先修改,如何使用自定义挂钩?

更新 Next.js 路由查询更改的状态会导致无限循环

从 API 中提取映射数组后出现重复元素

使用 React 中的功能组件更改另一个组件的状态

如何使用 babel 将 SVG 转换为 React 组件?

下拉菜单在 AppBar 中未正确对齐