React - LocalStorage & State - кнопка переключения проблемы рендеринга - PullRequest
0 голосов
/ 30 сентября 2019

Я уже некоторое время сталкиваюсь с этой проблемой ...

У меня возникают трудности при использовании текущего состояния для отображения кнопки переключения, которая добавляет и удаляет элемент в локальном хранилище. Приведенный ниже код добавляет и удаляет правильно, но не отображает правильно.

Состояние отражает то, что находится в хранилище, но (я считаю) асинхронная природа состояния позволяет отображать кнопки только для работыв одну сторону. При добавлении элемента кнопка изменится с добавления (+) на удаление (x), но не наоборот. В предыдущем состоянии кнопка постоянно отображается в виде креста.

Является ли это фундаментальным заблуждением о функционировании React - является ли это решение враждебным по отношению к его архитектуре, или есть небольшое изменение, которое позволило бы этой функции бытьпонял?

Извинения за то, что не изолировал проблемную область кода, но это ключевой вопрос - я не знаю, что мешает моим усилиям.

CodeSandBox к примеру

РЕДАКТИРОВАТЬ: Удивительно, но пример CodeSandBox работает так, как я хочу, но локально эта проблема сохраняется. Что может быть причиной этого различия в производительности?

import React, { useState, useEffect } from "react";

function App() {
  const [data, setData] = useState(null);
  const [input, setInput] = useState("");
  const [item, setItem] = useState("");
  const [favourites, setFavourites] = useState([]);

  const favsLS = localStorage.getItem("drinks");

// Loads localStorage into state
  useEffect(() => {
    if (favsLS && favsLS.length > 15) {
      setFavourites(JSON.parse(localStorage.getItem("drinks")).filter(n => n));
    }
  }, []);

// Adds/Removes item from state
  useEffect(() => {
    if (!JSON.stringify(favourites).includes(item.id)) {
      setFavourites(favourites => [...favourites, item]);
    } else {
      favourites.forEach((drink, index) => {
        let favs = favourites;
        if (item.id === drink.id) {
          favs.splice(index, 1);
          setFavourites(favs);
        }
      });
    }
  }, [item]);

// Commits state to localStorage
  useEffect(() => {
    localStorage.setItem("drinks", JSON.stringify(favourites));
  }, [favourites]);

  const handleChange = e => {
    setInput(e.target.value);
  };

// AJAX call
  const handleSubmit = async e => {
    e.preventDefault();
    let cocktail = input;
    const res = await fetch(
      `https://www.thecocktaildb.com/api/json/v1/1/search.php?s=${cocktail}`
    );
    const data = await res.json();
    setData(data.drinks);
    setInput("");
  };

  return (
    <div className='field'>
      <h3>Search</h3>
      <form onSubmit={handleSubmit}>
        <input placeholder={"Enter..."} value={input} onChange={handleChange} />
        <input type='submit' value='Submit' />
      </form>
      <div className='cocktails'>
        {data ? data.map((item, i) => (
              <div key={item.idDrink} className='card'>
                <h3>{item.strDrink}</h3>
                <div>
                  <button
                    className='fav-btn'
                    onClick={() => {
                      setItem({
                        id: item.idDrink,
                        name: item.strDrink,
                        image: item.strDrinkThumb
                      });
                      setFavourites(
                        JSON.parse(localStorage.getItem("drinks")).filter(n => n));
                    }}>
                    {JSON.stringify(favourites).includes(item.idDrink) ? "x" : "+"}
                  </button>
                  <img
                    className='cocktailImg'
                    src={item.strDrinkThumb}
                    alt=''
                  />
                </div>
              </div>
            ))
          : ""}
      </div>
    </div>
  );
}

export default App;

1 Ответ

0 голосов
/ 30 сентября 2019

Panther обнаружил проблему - два вызова для обновления одного и того же значения состояния. При удалении вызова setFavourites в рендере и перемещении фильтра (.filter (n => n)) в соответствии с его использованием. Эффект был удален.

...