TL;DR – if the state changes are triggered asynchronously (e.g. wrapped in a promise), they will not be batched; if they are triggered directly, they will be batched.
I've set up a sandbox to try this out: https://codesandbox.io/s/402pn5l989
import React, { Fragment, useState } from 'react';
import ReactDOM from 'react-dom';
import './styles.css';
function Component() {
  const [a, setA] = useState('a');
  const [b, setB] = useState('b');
  console.log('a', a);
  console.log('b', b);
  function handleClickWithPromise() {
    Promise.resolve().then(() => {
      setA('aa');
      setB('bb');
    });
  }
  function handleClickWithoutPromise() {
    setA('aa');
    setB('bb');
  }
  return (
    <Fragment>
    <button onClick={handleClickWithPromise}>
      {a}-{b} with promise
    </button>
    <button onClick={handleClickWithoutPromise}>
      {a}-{b} without promise
    </button>
      </Fragment>
  );
}
function App() {
  return <Component />;
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
I've made two buttons, one triggers the state changes wrapped in a promise like in your code example, the other triggers the state changes directly.
If you look at the console, when you hit the button “with promise”, it will first show a aa and b b, then a aa and b bb.
So the answer is no, in this case, it will not render aa - bb right away, each state change triggers a new render, there is no batching.
However, when you click the button “without promise”, the console will show a aa and b bb right away.
So in this case, React does batch the state changes and does one render for both together.