#reactjs
#reactjs
Вопрос:
У меня есть трудоемкий цикл для таблицы, которая выводит около 300 ячеек с некоторыми пользовательскими вычислениями для каждой, загрузка занимает 4-5 секунд, что имеет смысл. Поэтому я хочу отобразить режим загрузки, пока он делает это. Однако модальный отображается только после завершения дорогостоящего цикла?
const [loading, setLoading] = useState<boolean>(false);
useEffect(() => {
if(loading){
console.log(loading, "Loading has started")
}
}, [loading])
return(
<>
<Modal show={loading}>Loading....</Modal>
<a onClick={() => setLoading(true)}>Load more</a>
// Expensive loop
array.map(() => {
// HMTL
<div>
----
</div>
})
</>
)
Я вижу из журнала консоли, что состояние для «загрузки» было обновлено, но модальное еще не отображено, поэтому я предполагаю, что оно ожидает завершения цикла (чего я не хочу). Есть ли способ заставить его сначала выводить html для модального, или я упускаю фундаментальную часть реакции?
Ответ №1:
Если это медленное вычисление, вы, вероятно, не захотите делать это при каждом рендеринге, поскольку компоненты могут отображаться довольно много раз. В идеале вы хотите визуализировать только те дорогостоящие вычисления, когда входные данные изменяются, что может быть достигнуто путем разделения обработки и рендеринга.
Я не уверен, что полностью понимаю, как работает загрузочная часть, но что-то вроде этого примера должно помочь:
const [loading, setLoading] = useState<boolean>(false);
const [computedArray, setComputedArray] = useState([]);
useEffect(() => {
setComputedArray(array.map(//expensive loop here))
setLoading(false)
}, [array])
useEffect(() => {
if(loading){
console.log(loading, "Loading has started")
}
}, [loading])
return(
<>
<Modal show={loading}>Loading....</Modal>
<a onClick={() => setLoading(true)}>Load more</a>
// Cheap loop, turn data into markup
computedArray.map(() => {
// HTML
<div>
----
</div>
})
</>
)
Комментарии:
1. Полагаю, мне следовало упомянуть, что внутри дорогостоящего цикла массива есть и другие компоненты. Но вы говорите, что я должен вычислить их все, включая HTML-вывод вне этого рендеринга?
2. @CerIs это зависит от того, насколько легко разделить дорогостоящие части на части, превращающие данные в разметку, я обычно конвертирую их в html при каждом рендеринге, но если это невозможно, вы должны быть в порядке, предварительно вычисляя его, если ваши зависимости от эффекта использования верны
Ответ №2:
Я не знаю, что Modal
из этого следует, поэтому отвечаю с общей точки зрения:
Лично я бы сохранил массив в состоянии и обновил его в отдельной функции, а также использовал amp;amp;
символ для отображения загружаемого элемента. Таким образом, вы сохраняете всю свою логику относительно дорогостоящего расчета и погрузки / разгрузки в одном месте.
export default function App() {
const [loading, setLoading] = useState(false);
const [array, setArray] = useState([]);
const getExpensiveCalculation = async () => {
setLoading(true);
const resultOfExpensiveCalculation = await ... // something here
// assuming result is a spreadable array too
setArray([...array, ...resultOfExpensiveCalculation]);
setLoading(false);
};
return (
<>
{loading amp;amp; <Modal>Loading....</Modal>}
<a onClick={getExpensiveCalculation}>Load more</a>
{array.map(element => (
<div>
---
</div>
))}
</>
);
}