Вы можете объединить состояние loading
и состояние data
в один объект состояния, а затем сделать один вызов setState
, и будет только один рендеринг.
Примечание: В отличие от setState
в компонентах класса, setState
, возвращаемое из useState
, не объединяет объекты с существующим состоянием, оно полностью заменяет объект.Если вы хотите выполнить слияние, вам нужно прочитать предыдущее состояние и объединить его с новыми значениями самостоятельно.Обратитесь к документам .
. Я бы не стал слишком беспокоиться о том, чтобы вызывать рендеры, пока вы не решите, что у вас есть проблема с производительностью.Рендеринг (в контексте React) и фиксация обновлений виртуального DOM в реальном DOM - разные вопросы.Рендеринг здесь относится к генерации виртуальных DOM, а не к обновлению DOM браузера.React может пакетировать вызовы setState
и обновлять DOM браузера, указав окончательное новое состояние.
const {useState, useEffect} = React;
function App() {
const [userRequest, setUserRequest] = useState({
loading: false,
user: null,
});
useEffect(() => {
// Note that this replaces the entire object and deletes user key!
setUserRequest({ loading: true });
fetch('https://randomuser.me/api/')
.then(results => results.json())
.then(data => {
setUserRequest({
loading: false,
user: data.results[0],
});
});
}, []);
const { loading, user } = userRequest;
return (
<div>
{loading && 'Loading...'}
{user && user.name.first}
</div>
);
}
ReactDOM.render(<App />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
Альтернатива - написать собственный хук слияния состояний
const {useState, useEffect} = React;
function useMergeState(initialState) {
const [state, setState] = useState(initialState);
const setMergedState = newState =>
setState(prevState => Object.assign({}, prevState, newState)
);
return [state, setMergedState];
}
function App() {
const [userRequest, setUserRequest] = useMergeState({
loading: false,
user: null,
});
useEffect(() => {
setUserRequest({ loading: true });
fetch('https://randomuser.me/api/')
.then(results => results.json())
.then(data => {
setUserRequest({
loading: false,
user: data.results[0],
});
});
}, []);
const { loading, user } = userRequest;
return (
<div>
{loading && 'Loading...'}
{user && user.name.first}
</div>
);
}
ReactDOM.render(<App />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>