React State 更新时同步更新 dom -- flushSync 方法

一般情况下,State 更新是异步更新 dom 的,比如下边这个例子

import { useState, useRef } from 'react';
import { flushSync } from 'react-dom';

export default function TodoList() {
  const [todos, setTodos] = useState(
    Array(3).fill('').map((_, index) => ({
      id: `${index + 1}`,
      name: `todo_${index + 1}`
    }))
  );

  function handleAdd() {
      setTodos(todos => [ ...todos, { 
        id: `${todos.length + 1}`, 
        name: `todo_${todos.length + 1}`,
      }]);   
      
    // 这里是拿不到 input 的,因为这时候 dom 还没更新上   
    const input = document.getElementById(`${todos.length + 1}`);
    console.log(' --input--', input);
  }

  return (
    <>
      <button onClick={handleAdd}>
        Add
      </button>
      <div>
        {todos.map(item => {
          const { name, id } = item;
          return (
            <div key={id}>
              <input id={id} value={id}  />
              {name}
            </div>
          )
        })}
      </div>
    </>
  );
}

在这里插入图片描述

这时候可以使用 react-dom 提供的 flushSync,使得同步更新 dom:

import { useState, useRef } from 'react';
import { flushSync } from 'react-dom';

export default function TodoList() {
  const [todos, setTodos] = useState(
    Array(3).fill('').map((_, index) => ({
      id: `${index + 1}`,
      name: `todo_${index + 1}`
    }))
  );

  function handleAdd() {
  	// 在这里调用,会同步更新 dom
    flushSync(() => {
      setTodos(todos => [ ...todos, { 
        id: `${todos.length + 1}`, 
        name: `todo_${todos.length + 1}`,
      }]);      
    });
    // 这时候这里拿到的 input 就是有的,因为 dom 已经同步渲染出来了
    const input = document.getElementById(`${todos.length + 1}`)
    console.log(' --input--', input.value)
  }

  return (
    <>
      <button onClick={handleAdd}>
        Add
      </button>
      <div>
        {todos.map(item => {
          const { name, id } = item;
          return (
            <div key={id}>
              <input id={id} value={id}  />
              {name}
            </div>
          )
        })}
      </div>
    </>
  );
}

但会有一个点:虽然调用 flushSync 同步更新 dom,但是组件的 state 更新仍然是异步的;

  const [todos, setTodos] = useState(
    Array(3).fill('').map((_, index) => ({
      id: `${index + 1}`,
      name: `todo_${index + 1}`
    }))
  );
  
  function handleAdd() {
    flushSync(() => {
      setTodos(todos => [ ...todos, { 
        id: `${todos.length + 1}`, 
        name: `todo_${todos.length + 1}`,
      }]);      
    });
    const input = document.getElementById(`${todos.length + 1}`)
    console.log(' --input--', input.value);

	// 这里拿到的还是 旧值
	console.log('todos: ', todos);
  }
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值