【问题标题】:How to avoid rerender of a component in React?如何避免在 React 中重新渲染组件?
【发布时间】:2020-12-13 23:14:33
【问题描述】:

使用 React 和 Redux 创建一个简单的应用程序。

重点是从服务器获取照片,显示它们,如果您单击照片显示模式窗口,则显示更大的照片和 cmets。

App组件代码

import React, { useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import './App.scss'
import List from './components/list/List'
import Header from './components/header/Header'
import Footer from './components/footer/Footer'
import ModalContainer from './containers/ModalContainer'
import { getPhotos, openModal } from './redux/actions/actions'

const App = () => {

  const { isFetching, error } = useSelector(({ photos }) => photos)
  const photos = useSelector(({ photos }) => photos.photos)
  const { isOpen } = useSelector(({ modal }) => modal)
  const dispatch = useDispatch()
  
  useEffect(() => {
    dispatch(getPhotos())
  }, [])

  const getBigPhoto = (id) => {
    dispatch(openModal(id))
  }

  return (
    <div className="container">
      <Header>Test App</Header>
      <div className="list__content">
        {isFetching 
          ? <p>Loading...</p>
          : error 
          ? <p>{error}</p>
          : photos.map(({ id, url }) => (
              <List
                key={id}
                src={url}
                onClick={() => getBigPhoto(id)}
              />
            ))
        }
      </div>
      <Footer>&copy; 2019-2020</Footer>
      {isOpen && <ModalContainer />}
    </div>
  )
} 

export default App

在这一行中,如果我刷新页面,我只会获取一次照片以停止重新渲染

  useEffect(() => {
    dispatch(getPhotos())
  }, [])

当我点击照片时,我的模态打开了,我想停止重新渲染所有组件。例如对于我的标题,我像这样使用 React.memo HOC

import React, { memo } from 'react'
import './Header.scss'
import PropTypes from 'prop-types'

const Header = memo(({ children }) => {
  return <div className="header">{children}</div>
})

Header.propTypes = {
  children: PropTypes.string,
}

Header.defaultProps = {
  children: '',
}

export default Header

当我打开和关闭我的模式时,它可以完美运行。页眉和页脚不会重新呈现。但是每次我打开和关闭模式窗口时都会重新呈现 List 组件。发生这种情况是因为 List 组件中的 onClick={() =&gt; getBigPhoto(id)} 每次单击都会创建一个新的匿名函数。如您所知,如果您的道具发生变化,组件将重新渲染。

我的问题是如何避免在我的情况下重新呈现 List 组件?

【问题讨论】:

  • List组件也可以使用备忘录
  • @Shubham Verma,不起作用,因为每次点击时 onClick 道具都包含一个新功能
  • 有两种方法,要么在列表中使用`memo`,要么使用useCallback。在备忘录中,您还可以传递条件来比较何时渲染或不渲染。在 useCallback 中,你可以传递依赖数组让 react 知道何时创建新函数。

标签: javascript reactjs redux


【解决方案1】:

您可以为 List 创建一个接收 getBigPhoto 和一个 id 的容器,使用 useCallback 创建 getBigPhoto,这样函数就不会改变:

const ListContainer = React.memo(function ListContainer({
  id,
  src,
  getBigPhoto,
}) {
  return (
    <List
      key={id}
      src={scr}
      onClick={() => getBigPhoto(id)}
    />
  );
});
const App = () => {
  const { isFetching, error, photos } = useSelector(
    ({ photos }) => photos
  );
  const { isOpen } = useSelector(({ modal }) => modal);
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(getPhotos());
  }, []);
  //use callback so getBigPhoto doesn't change
  const getBigPhoto = React.useCallback((id) => {
    dispatch(openModal(id));
  }, []);

  return (
    <div className="container">
      <Header>Test App</Header>
      <div className="list__content">
        {isFetching ? (
          <p>Loading...</p>
        ) : error ? (
          <p>{error}</p>
        ) : (
          photos.map(({ id, url }) => (
            // render pure component ListContainer
            <ListContainer
              key={id}
              src={url}
              id={id}
              getBigPhoto={getBigPhoto}
            />
          ))
        )}
      </div>
      <Footer>&copy; 2019-2020</Footer>
      {isOpen && <ModalContainer />}
    </div>
  );
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-21
    • 2019-04-27
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 2018-04-05
    • 1970-01-01
    相关资源
    最近更新 更多