使用 useState 钩子时react组件渲染两次

IT技术 javascript reactjs react-hooks
2022-07-12 23:52:35

我一直无法理解为什么我的 App react 组件会渲染两次,如下图所示。

在此处输入图像描述

我在返回组件之前插入了一个 console.log,以查看我的组件渲染了多少次。

每当我删除 useState 钩子时,我的应用程序只会按我想的那样呈现一次。欢迎任何关于为什么会发生这种情况的指导

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

const ListItem = ({ title, url, author, num_comments, points }) => {
  return (
    <div>
      <span>
        <a href={url} target='_blank' rel='noopener noreferrer'>
          {title}
        </a>{' '}
        by {author}
      </span>
      <br />
      <span>Comments: {num_comments}</span>
      <br />
      <span>Points: {points}</span>
      <hr />
    </div>
  );
};

const List = ({ list }) => {
  return list.map(({ objectID, ...item }) => (
    <ListItem key={objectID} {...item} />
  ));
};

const Search = ({ search, onSearch }) => {
  return (
    <div>
      <label htmlFor='search'>Search: </label>
      <input id='search' type='text' value={search} onChange={onSearch} />
      <p>
        Searching for <strong>{search}</strong>
      </p>
    </div>
  );
};

const App = () => {
  const stories = [
    {
      title: 'React',
      url: 'https://reactjs.org/',
      author: 'Jordan Walke',
      num_comments: 3,
      points: 4,
      objectID: 0,
    },
    {
      title: 'Redux',
      url: 'https://redux.js.org/',
      author: 'Dan Abramov, Andrew Clark',
      num_comments: 2,
      points: 5,
      objectID: 1,
    },
  ];

  const [search, setSearch] = useState(localStorage.getItem('search') || '');

  useEffect(() => {
    localStorage.setItem('search', search);
  }, [search]);

  const handleSearch = (event) => {
    setSearch(event.target.value);
  };

  console.log('rendered');

  return (
    <div className='App'>
      <h1>My Hacker Stories</h1>
      <Search search={search} onSearch={handleSearch} />
      <hr />
      <List
        list={stories.filter((story) =>
          story.title.toLowerCase().includes(search.toLowerCase())
        )}
      />
    </div>
  );
};

export default App;
4个回答

看看这个:https ://github.com/facebook/react-devtools/issues/1297

“意外的重新渲染”实际上并不是由 useEffect 引起的,而是 DevTools 通过单独重新渲染函数组件来“检查”挂钩值的方式。

虽然我知道在某些情况下意外渲染可能表明存在问题,但由于以下几个原因,这个特定的渲染实际上不应该是一个问题:

渲染不是递归的。(不渲染子组件。)渲染只发生在安装了 DevTools 的用户身上,即使那样——也只会影响单个组件(当前在树中选择的那个)。渲染没有副作用(例如 DOM 不会被更新)。

甚至我想知道为什么我的控件会渲染两次。

我的大多数组件中都没有 useEffect 挂钩,而且大多数情况下我只是在用户在输入框中输入数据时设置状态(不可变)。这也发生在每个具有两个为什么绑定的组件中。

DevTools: 我在没有安装 devtools 的浏览器中尝试了我的应用程序,但仍然是同样的问题。

React.StrictMode 我认为这是潜在的罪魁祸首。当我从 index.js 中删除这个标签时,所有组件都开始正常工作。我还在官方文档中读到,strictMode 检查仅在开发模式下执行,在生产构建中被忽略。

这让我觉得我们的代码是正确的,我们可以忽略 dev.js 中的重新渲染问题。

您的“setSearch”正在更新输入框的 vue,然后您的“useEffect”在搜索更改时再次更新它。

删除 useEffect

然后

const handleSearch = (event) => {
    setSearch(event.target.value);
    localStorage.setItem('search', event.target.value)
  }

这是一个沙盒链接:https ://codesandbox.io/s/dawn-night-h2xiz?file=/src/App.js

它确实不能解决它,但可能会在将来避免一些问题。

双渲染应该只发生在开发模式而不是生产模式。在此处查看 Dan Abramov 的回复: https ://github.com/facebook/react/issues/15074

我同意@denislexic,这是解决问题的一种方法。

代替

useEffect(() => {
  localStorage.setItem('search', search);
}, [search]);

const handleSearch = (event) => {
  setSearch(event.target.value);
};

让我们执行以下操作:

const handleSearch = (event) => {
  const search = event.target.value;
  setSearch(search);
  localStorage.setItem('search', search);
};

这在一个例程中完成了相同的 2 个任务(保存到 state 和 localStorage)而不是 2 个。提示:useEffect 导致重新渲染

希望有帮助。

干杯! 🍻