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

 1import { useState, useRef } from 'react';
 2import { flushSync } from 'react-dom';
 3
 4export default function TodoList() {
 5  const [todos, setTodos] = useState(
 6    Array(3).fill('').map((_, index) => ({
 7      id: `${index + 1}`,
 8      name: `todo_${index + 1}`
 9    }))
10  );
11
12  function handleAdd() {
13      setTodos(todos => [ ...todos, { 
14        id: `${todos.length + 1}`, 
15        name: `todo_${todos.length + 1}`,
16      }]);   
17      
18    
19    const input = document.getElementById(`${todos.length + 1}`);
20    console.log(' --input--', input);
21  }
22
23  return (
24    <>
25      <button onClick={handleAdd}>
26        Add
27      </button>
28      <div>
29        {todos.map(item => {
30          const { name, id } = item;
31          return (
32            <div key={id}>
33              <input id={id} value={id}  />
34              {name}
35            </div>
36          )
37        })}
38      </div>
39    </>
40  );
41}

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

 1import { useState, useRef } from 'react';
 2import { flushSync } from 'react-dom';
 3
 4export default function TodoList() {
 5  const [todos, setTodos] = useState(
 6    Array(3).fill('').map((_, index) => ({
 7      id: `${index + 1}`,
 8      name: `todo_${index + 1}`
 9    }))
10  );
11
12  function handleAdd() {
13  	
14    flushSync(() => {
15      setTodos(todos => [ ...todos, { 
16        id: `${todos.length + 1}`, 
17        name: `todo_${todos.length + 1}`,
18      }]);      
19    });
20    
21    const input = document.getElementById(`${todos.length + 1}`)
22    console.log(' --input--', input.value)
23  }
24
25  return (
26    <>
27      <button onClick={handleAdd}>
28        Add
29      </button>
30      <div>
31        {todos.map(item => {
32          const { name, id } = item;
33          return (
34            <div key={id}>
35              <input id={id} value={id}  />
36              {name}
37            </div>
38          )
39        })}
40      </div>
41    </>
42  );
43}

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

 1const [todos, setTodos] = useState(
 2    Array(3).fill('').map((_, index) => ({
 3      id: `${index + 1}`,
 4      name: `todo_${index + 1}`
 5    }))
 6  );
 7  
 8  function handleAdd() {
 9    flushSync(() => {
10      setTodos(todos => [ ...todos, { 
11        id: `${todos.length + 1}`, 
12        name: `todo_${todos.length + 1}`,
13      }]);      
14    });
15    const input = document.getElementById(`${todos.length + 1}`)
16    console.log(' --input--', input.value);
17
18    
19    console.log('todos: ', todos);
20  }
个人笔记记录 2021 ~ 2025