React - LocalStorage & State - 按钮切换渲染问题
React - LocalStorage & State - button toggle rendering issue
我一直在努力解决这个问题......
我在利用当前状态显示切换按钮时遇到困难,该按钮既可以向本地存储添加项目,也可以从本地存储中删除项目。下面的代码正确添加和删除,但没有正确呈现。
状态是存储中的镜像,但(我相信)状态的异步性质允许按钮的呈现仅以一种方式工作。添加项目时,按钮将从添加 (+) 更改为删除 (x),但反之则不会。以前的状态使按钮永久呈现为十字。
这是对 React 功能的基本误解吗?这个解决方案是否不利于它的架构,或者是否有一个小的改变可以实现这个功能?
抱歉没有隔离代码的问题区域,但这是一个关键问题 - 我不知道是什么阻碍了我的努力。
编辑:令人惊讶的是,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;
Panther 发现了问题 - 两次调用更新相同的状态值。通过在渲染中删除对 setFavourites 的调用,并将过滤器 (.filter(n => n)) 移动到其相应的 useEffect,错误被删除。
我一直在努力解决这个问题......
我在利用当前状态显示切换按钮时遇到困难,该按钮既可以向本地存储添加项目,也可以从本地存储中删除项目。下面的代码正确添加和删除,但没有正确呈现。
状态是存储中的镜像,但(我相信)状态的异步性质允许按钮的呈现仅以一种方式工作。添加项目时,按钮将从添加 (+) 更改为删除 (x),但反之则不会。以前的状态使按钮永久呈现为十字。
这是对 React 功能的基本误解吗?这个解决方案是否不利于它的架构,或者是否有一个小的改变可以实现这个功能?
抱歉没有隔离代码的问题区域,但这是一个关键问题 - 我不知道是什么阻碍了我的努力。
编辑:令人惊讶的是,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;
Panther 发现了问题 - 两次调用更新相同的状态值。通过在渲染中删除对 setFavourites 的调用,并将过滤器 (.filter(n => n)) 移动到其相应的 useEffect,错误被删除。