#javascript #reactjs #react-native #asynchronous #async-await
#javascript #reactjs #реагирующий-родной #асинхронный #асинхронный -ожидание
Вопрос:
Описание моей текущей ситуации:
Я разрабатываю приложение для продажи книг и использую контекст React для обмена состоянием между экранами. Когда я вхожу в экран книги, у меня есть две кнопки (пользовательские дочерние компоненты) «добавить в корзину» и «сохранить», которые при монтировании извлекают их соответствующее начальное состояние (добавленное в корзину или сохраненное соответственно) в моей БД.
Проблема
Когда кнопка «добавить в корзину» завершает получение своего начального состояния из базы данных, она обновляет свое родительское состояние «currentBookData» с помощью обратного вызова, который получает как prop.
То же самое для другой кнопки.
Вот код для экрана моей книги:
function BookScreen(props) { //
const [bookData, setBookData] = useState(props.params.selectedBookData);
const handleButtonAddToCartLoad = (isAddedToCart) => {
const {currentUser} = props; // provided by the context
// !!!!!!!!!!!!!!!!!!!!!!!
const newBookData = { ...bookData, isAddedToCart };
setBookData(newBookData);
currentUser.addVisitedBook(newBookData.id, newBookData); // Update the book in the map of visited books
}
const handleButtonSaveLoad = (isSaved) => {
const {currentUser} = props; // provided by the context
// !!!!!!!!!!!!!!!!!!!!!!!
const newBookData = { ...bookData, isSaved };
setBookData(newBookData);
currentUser.addVisitedBook(newBookData.id, newBookData); // Update the book in the map of visited books
}
useEffect(() => {
// When the screen mounts, update the book data if it wasn't fetched previously
(async () => {
const {currentUser} = props; // provided by the context
if(!currentUser.getVisitedBook(bookData.id)) {
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
const newBookData = await db.getBook(bookData.id);
// Add the book to the visited books of list
currentUser.addVisitedBook(newBookData.id, newBookData );
}
})();
}, []);
return (
<View>
...
<AddToCartButton bookId={bookData.id} onLoad={handleButtonAddToCartLoad } />
<SaveButton bookId={bookData.id} onLoad={handleButtonSaveLoad} />
</View>
)
}
export default withCurrentUser(BookScreen); // <------ It consumes the context where I have a Map with all the data which has been downloaded from the DB. Just to avoid unnecessary requests.
Как вы можете себе представить после прочтения кода, я обновляю состояние, используя обычный стандартный хук, предоставляемый React. Происходит то, что обновления поступают одновременно, поэтому состояние не «объединяется», оно всегда совпадает с последним обновлением:
{
id: "bookId",
title: "bookTitle",
isAddedToCart: false,
}
или
{
id: "bookId",
title: "bookTitle",
isSaved: true,
}
или иногда
{
id: "bookId",
title: "bookTitle",
}
но никогда не то, что мне нужно, чтобы это было
{
id: "bookId",
title: "bookTitle",
isAddedToCart: false,
isSaved: true,
}
Есть идеи, как решить эту проблему с помощью хуков??
Комментарии:
1. reactjs.org/docs/hooks-reference.html#functional-updates
2. И возможно ли сделать что-то подобное? позвольте _prevData; setData(prevData => { _prevData = prevData; return prevData; } просто переместить его из локальной области?
3. Нет, обратный вызов вызывается асинхронно. Просто выполните агрегацию внутри обратного вызова и верните новое состояние из обратного вызова.
4. Чувак, последний вопрос. Будет ли это то же самое, чтобы использовать этот пользовательский хук? blog.logrocket.com/… Или тот, который вы мне показываете, — единственный способ получить доступ к предыдущему состоянию при его обновлении?
5. На мой взгляд , использование этого пользовательского хука для получения предыдущего состояния немного пахнет кодом. Да, вы могли бы его использовать, но, по моему опыту, код, который зависит от него, будет иметь тенденцию быть беспорядочным. Если вы хотите избежать передачи обратного вызова в
setData()
и способ объединения новых данных с предыдущими данными всегда один и тот же, тогда вы можете изменить свойuseState()
наuseReducer()
.