У меня есть компонент, который я обновляю от запуска простой функции при каждом рендеринге до компонента, который запускается только при обновлении некоторых компонентов:
// dummy functions to simulate calling a service asynchronously
const timeout = ms => new Promise(resolve => setTimeout(resolve, ms));
const sleep = async fn => {
await timeout(3000);
return fn();
};
// imitation of the function
const {useState, useEffect, useCallback} = React;
const CHECKOUT_COUNT_STATE = {NONE:'none', COUNTING:'counting', SUBMITTED:'submitted'};
const Example = () => {
const [count, setCount] = useState(-1); //uses a redux selector in the real code
const [countState, setCountState] = useState(CHECKOUT_COUNT_STATE.NONE); //uses a redux selector in the real code
const [checkoutComponent, setCheckoutComponent] = useState(
<span> Estimated Stock Count:
<strong data-co="stock count">Not calculated</strong>
</span>
);
useEffect(()=> {
if(countState === CHECKOUT_COUNT_STATE.SUBMITTED){
setCheckoutComponent(<strong>Stock request being submitted…</strong>)
} else {
setCheckoutComponent(
<span>Estimated Stock Count: {
countState === CHECKOUT_COUNT_STATE.COUNTING?
<strong>Calculating…</strong> :
<strong data-co="stock count">{count !== -1? count : 'Not Calculated'}</strong>
}
</span>
);
}
}, [count, countState])
// dummy code to simulate async call
const checkStock = useCallback(async () => {
await sleep(()=>{
setCount(Math.floor(Math.random() * (101)));
setCountState(CHECKOUT_COUNT_STATE.NONE);
});
});
return (
<div>
<p>Stock Counter</p>
<div>{checkoutComponent}</div>
<button onClick={()=>{
setTimeout(setCountState(CHECKOUT_COUNT_STATE.COUNTING), 0); checkStock()}
}>
Check Stock
</button>
<button onClick={() => setCountState(CHECKOUT_COUNT_STATE.SUBMITTED)}>Submit Request</button>
</div>
);
};
// Render it
ReactDOM.render(
<Example title="Example using Hooks:" />,
document.getElementById("react")
);
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.25/browser-polyfill.min.js"></script>
</head>
<body>
<div id="react"></div>
</body>
Я видел вопросы stackoverflow, которые рекомендуют против этого, но, не усложняя jsx-часть компонента, с условным рендерингом различных частей, я не могу придумать лучшего способа добиться того же поведения.