Я новичок в React и государственных хуках. Я пытаюсь создать веб-сайт о создании списка книг и сохранении его в локальном хранилище. Также загрузка изображения в облачный. Моя проблема в том, когда я пытаюсь сохранить URL-адрес облачного изображения в локальное хранилище, он сохраняет предыдущий URL-адрес. Я думаю, что у меня проблема с хуками useState, useEffect, но я не мог этого понять. Ниже мой код.
LocalStorage.js
import React, { useState, useEffect } from 'react'
import BookList from '../../components/BookList'
import CreateBook from '../../components/CreateBook'
const getLocalStorage = () => {
let list = localStorage.getItem('liste')
if (list) {
return JSON.parse(localStorage.getItem('liste'))
} else {
return []
}
}
const LocalStorage = () => {
//state hooks
const [list, setList] = useState(getLocalStorage)
const [bookName, setBookName] = useState('')
const [writerName, setWriterName] = useState('')
const [pageNumber, setPageNumber] = useState('')
const [info, setInfo] = useState('')
const [image, setImage] = useState('')
const [uploadUrl, setUploadUrl] = useState('')
let id
//Function for submit button
const handleSubmit = async (e) => {
e.preventDefault()
// conditions for fill the blanks
if (!bookName || !writerName || !pageNumber || !image) {
setInfo('Please fill the blanks')
} else {
try {
const data = new FormData()
data.append('file', image)
data.append('upload_preset', 'book-list-project')
data.append('cloud_name', 'book-list')
let response = await fetch(
'https://api.cloudinary.com/v1_1/book-list/image/upload',
{
method: 'POST',
body: data,
}
)
let result = await response.json()
setUploadUrl(result.url)
id = new Date().getTime().toString()
const newBook = {
id: id,
bookName: bookName,
writerName: writerName,
pageNumber: pageNumber,
uploadUrl: uploadUrl,
}
setList([...list, newBook])
setBookName('')
setWriterName('')
setPageNumber('')
setInfo('Book created')
setImage('')
} catch (error) {
console.log(error)
}
}
}
//Function for remove specific book from local storage
const removeSpecificBook = (id) => {
setList(list.filter((book) => book.id !== id))
}
// Function for clear all books from local storage
const removeAllBooks = () => {
setList([])
}
useEffect(() => {
localStorage.setItem('liste', JSON.stringify(list))
}, [list])
return (
<div>
<CreateBook
bookName={bookName}
writerName={writerName}
pageNumber={pageNumber}
handleSubmit={handleSubmit}
info={info}
setBookName={setBookName}
setWriterName={setWriterName}
setPageNumber={setPageNumber}
setImage={setImage}
/>
<BookList
items={list}
removeSpecificBook={removeSpecificBook}
removeAllBooks={removeAllBooks}
/>
</div>
)
}
export default LocalStorage
Booklist.js
import React from 'react'
const BookList = ({ items, removeSpecificBook, removeAllBooks }) => {
return (
<div className="container mx-auto">
<div className="mt-20 flex flex-wrap items-center justify-center">
{items.map((item) => {
return (
<div key={item.id} className="p-2 m-2 bg-yellow-100 w-1/4">
<div className="p-1 m-1 flex justify-center">
<img
className="object-contain h-52 w-52"
src={item.uploadUrl}
alt="some img"
/>
</div>
<div className="p-1 m-1">
<h5 className="font-semibold">Book Name</h5>
<h3>{item.bookName}</h3>
</div>
<div className="p-1 m-1">
<h5 className="font-semibold">Writer Name</h5>
<h3>{item.writerName}</h3>
</div>
<div className="p-1 m-1">
<h5 className="font-semibold">Total Page</h5>
<h3>{item.pageNumber}</h3>
</div>
<div className="flex justify-end">
<button
onClick={() => removeSpecificBook(item.id)}
className="px-4 py-2 bg-red-500 rounded-full text-white"
>
Remove
</button>
</div>
</div>
)
})}
</div>
{items.length > 1 && (
<div className="flex justify-center my-5">
<button
onClick={removeAllBooks}
className="px-8 py-4 bg-red-500 rounded-full text-white"
>
Remove All
</button>
</div>
)}
</div>
)
}
export default BookList
CreateBook.js
import React from 'react'
const CreateBook = ({
bookName,
writerName,
pageNumber,
handleSubmit,
info,
setBookName,
setWriterName,
setPageNumber,
setImage,
}) => {
return (
<div>
<div>
<nav className="bg-blue-500 text-center text-white px-6 py-3">
Create Book
</nav>
</div>
<div className="bg-red-200 mx-auto w-96 rounded-lg flex justify-center mt-20">
<form onSubmit={handleSubmit}>
<div>
<div className="p-3 text-center">
<h6>Enter Book Name</h6>
<input
value={bookName}
onChange={(e) => setBookName(e.target.value)}
className="rounded-md"
type="text"
placeholder="Book Name"
/>
</div>
<div className="p-3 text-center">
<h6>Enter Writer Name</h6>
<input
value={writerName}
onChange={(e) => setWriterName(e.target.value)}
className="rounded-md"
type="text"
placeholder="Writer Name"
/>
</div>
<div className="p-3 text-center">
<h6>Enter Total Page Number </h6>
<input
value={pageNumber}
onChange={(e) => setPageNumber(e.target.value)}
className="rounded-md"
type="number"
placeholder="Page Number"
/>
</div>
<div className="p-3 text-center">
<div>
<h6>Upload Image</h6>
</div>
<div className="p-3">
<input
type="file"
onChange={(e) => setImage(e.target.files[0])}
/>
</div>
</div>
<div className="flex justify-center p-3">
<button className="bg-blue-500 py-3 px-6 rounded-full text-white">
Submit
</button>
</div>
<div className="p-3 text-center text-white">
<h3>{info}</h3>
</div>
</div>
</form>
</div>
</div>
)
}
export default CreateBook
Также сообщите мне, если у вас есть предложения по структуре моего кода. У меня нет истории программирования, и я пытаюсь учиться с самого начала. Мне нужны все предложения, чтобы продолжить изучение программирования. Заранее спасибо.
1 ответ
Состояние не будет обновлено сразу после вызова функции установки состояния. На самом деле, когда вы вызываете функцию установки состояния, вы говорите React обновить значение состояния и запланировать повторный рендеринг. Это означает, что вы получите это значение при следующем рендеринге компонента. Лучшее объяснение того, как это работает, доступно в официальные документы.
Теперь, пожалуйста, взгляните глубже на то, что происходит внутри handleSubmit
сразу после получения ответа. Ты звонишь setUploadUrl(result.url)
и он сообщает React обновить uploadUrl
значение на следующем рендере. Электрический ток uploadUrl
значение не изменится. Таким образом, когда вы получите uploadUrl
значение несколько строк спустя у вас все еще будет то же значение, что и до вызова setUploadUrl
. Я знаю, что это может быть неожиданно, но как только вы к этому привыкнете, это станет совершенно нормальным. Продолжать!
Решение довольно простое. Просто используйте result.url
вместо uploadUrl
когда вы создаете newBook
:
const newBook = {
id: id,
bookName: bookName,
writerName: writerName,
pageNumber: pageNumber,
uploadUrl: result.url,
}