React函数式组件中实现「批量更新」的两种方式

React函数式组件中实现「批量更新」的两种方式

1 年前 · 来自专栏 《React 加油站》

首先看下下面的这段代码,在获取到数据后,分别更新了两个 State ,线上你是不是也是这样写的?

function NormalComponent() {
  const [list, setList] = useState(null)
  const [info, setInfo] = useState(null)
  useEffect(() => {
    ;(async () => {
      const data = await getApiData()
      setList(data.list)
      setInfo(data.info)
  }, [])
  return <div>非批量更新组件时 Render 次数{renderOnce("normal")}</div>

如果你也是这样写的,那么,这个组件会在 setList(data.list) 后触发组件的 Render 过程,然后在 setInfo( data.info ) 后再次触发 Render 过程,造成性能损失。那么应该怎么写才能实现批量更新呢?下面介绍两种方式:

1、将多个 State 合并为单个 State。例如使用 如下代码 替代 list 和 info 两个 State。

const [data, setData] = useState({ list: null, info: null })

2、使用 React 官方提供的 unstable_batchedUpdates 方法,将多次 setState 封装到 unstable_batchedUpdates 回调中,修改后代码如下。

function BatchedComponent() {
  const [list, setList] = useState(null)
  const [info, setInfo] = useState(null)
  useEffect(() => {
    ;(async () => {
      const data = await getData()
      unstable_batchedUpdates(() => {
        setList(data.list)
        setInfo(data.info)
  }, [])
  return <div>批量更新组件时 Render 次数{renderOnce("batched")}</div>

为啥回这样呢?

主要因为批量更新 setState 时,多次执行 setState 只会触发一次 Render 过程。相反在立即更新 setState 时,每次 setState 都会触发一次 Render 过程,就存在性能影响。

附验证demo:

import { useEffect, useState } from "react";
import { unstable_batchedUpdates } from "react-dom";
const renderCntMap = {};
function renderOnce(name) {
  return (renderCntMap[name] = (renderCntMap[name] || 0) + 1);
async function getData() {
  return {
    list: [1, 2, 3, 4],
    info: { name: "MoonBall" }
function NormalComponent() {
  const [list, setList] = useState(null);
  const [info, setInfo] = useState(null);
  useEffect(() => {
    (async () => {
      const data = await getData();
      setList(data.list);
      setInfo(data.info);
    })();
  }, []);
  return <div>非批量更新组件时 Render 次数{renderOnce("normal")}</div>;
function BatchedComponent() {
  const [list, setList] = useState(null);
  const [info, setInfo] = useState(null);
  useEffect(() => {
    (async () => {
      const data = await getData();
      unstable_batchedUpdates(() => {
        setList(data.list);
        setInfo(data.info);
    })();
  }, []);
  return <div>批量更新组件时 Render 次数{renderOnce("batched")}</div>;
export default function App() {
  return (
    <div className="App">
      <h1>批量更新验证 Render 次数</h1>