profile
viewpoint

Ask questionsReact Hooks will render multiple times after await

const [ html, setHTML ] = useState('');
const [ script, setScript ] = useState('');

const update = (script, html) => {
  setScript(script);
  setHTML(html);
};

update('a', 'b');

The above code works fine, React Hooks will render ONCE and combine setScript & setHTML;

const [ html, setHTML ] = useState('');
const [ script, setScript ] = useState('');

const update = async (script, html) => {
  await new Promise(resolve => setTimeout(resolve, 10));
  setScript(script);
  setHTML(html);
};

update('a', 'b');

The above code doesn't work anymore, React Hooks will render TWICE and it doesn't combine setScript & setHTML.

I can change to the code to:

const [ state, setState ] = useState({
  html: '',
  script: ''
});

const update = async (script, html) => {
  await new Promise(resolve => setTimeout(resolve, 10));
  setState({
    script,
    html
  });
};

update('a', 'b');

The above code only renders ONCE but it has a new bug: the cursor in the textArea (where script and html go) will move to the end of the textArea instead of staying at where it is.

facebook/react

Answer questions vkurchatkin

This is inevitable: when you run your code asynchronously, React has no way of knowing that more synchronous setters could be executed after the current one, so it has to trigger render for each. You can either batch by making a single state object, like you did, or use unstable_batchedUpdates:

import {unstable_batchedUpdates as batchedUpdates} from 'react-dom';

// ....

const [ html, setHTML ] = useState('');
const [ script, setScript ] = useState('');

const update = async (script, html) => {
  await new Promise(resolve => setTimeout(resolve, 10));
    batchedUpdates(() => {
        setScript(script);
        setHTML(html);
    });
};

update('a', 'b');
useful!

Related questions

Disable react strict mode on third party libraries hot 6
Refs - "object is not extensible" hot 4
Warning: Unknown DOM property for. Did you mean htmlFor? hot 4
React@16.9 block `javascript:void(0);` hot 4
TypeError: Object(...) is not a function hot 3
Warning: validateDOMNesting(...): <tr> cannot appear as a child of <table> hot 3
React custom hook "Should have a queue. This is likely a bug in React" error message. hot 2
useEffect causes 'callback is not a function' exception hot 2
DevTools: Updating state or props in devtools does not trigger component update. hot 2
Infinite loop in useEffect using blank object or array hot 2
False-positive security precaution warning (`javascript:` URLs) hot 2
Hooks API - hook breaks when exported from module hot 2
Function components do not support contextType. hot 2
Feedback on useEffect depndencies change error hot 2
[ESLint] Feedback for 'exhaustive-deps' lint rule hot 2
Github User Rank List