React useState, useEffect — сохранять переменные в локальное хранилище

Я новичок в 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 ответ
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,
    }

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *