我试图学习React钩子,并试图将现有的代码库转换为使用钩子,但是我很困惑。
在useEffect
内设置状态是否正常?如果这样做,是否会引起可怕的无限循环?
import React, { useState, useEffect } from 'react';
import App from 'next/app';
import Layout from './../components/Layout';
function MyApp({ Component, pageProps }) {
const [ cart, setCart ] = useState([]);
const addToCart = (product) => {
setCart((prevCartState) => {
return [ ...prevCartState, product ];
});
localStorage.setItem('cart', JSON.stringify(cart));
};
//mimicking componentDidMount to run some effect using useEffect
//useEffect(() => setCount((currentCount) => currentCount + 1), []);
useEffect(() => {
const cartCache = JSON.parse(localStorage.getItem('cart'));
//cart = cartCache; Good or bad?
cartCache || setCart(() =>{
});
}, []);
return <Component {...pageProps} />;
}
我原始的基于类的组件:
/*
export default class MyApp extends App {
state = {
cart: []
}
componentDidMount = () => {
const cart = JSON.parse(localStorage.getItem('cart'));
if (cart) {
this.setState({
cart
});
}
};
addToCart = (product) => {
this.setState({
cart: [...this.state.cart, product]
});
localStorage.setItem('cart', JSON.stringify(this.state.cart));
}
render() {
const { Component, pageProps } = this.props
return (
<contextCart.Provider value={{ cart: this.state.cart, addToCart: this.addToCart }}>
<Layout>
<Component {...pageProps} />
</Layout>
</contextCart.Provider>
)
}
}*/
答案 0 :(得分:2)
只要您不侦听依赖项数组中同一字段的更改,就可以在useEffect
中设置状态是可以的。在您的特定情况下,您仅调用一次useEffect
(因为您已经传递了一个空的依赖项数组)。
useEffect(() => {
const cartCache = JSON.parse(localStorage.getItem('cart'));
if (cartCache) {
setCart(cartCache);
}
}, []);
添加第二个useEffect
来收听cart
的更改并保持localStorage
为最新状态也很酷。
useEffect(() => {
localStorage.setItem('cart', JSON.stringify(cart));
}, [cart]);
答案 1 :(得分:2)
由于localStorage.getItem()
是同步调用,因此在这种情况下,您也可以使用useState
的函数回调版本来设置初始值。这样,您无需使用useEffect
。通常,如果可能的话,我会尽量避免在功能组件中引入任何新的副作用。
您可以尝试以下操作:
const [ cart, setCart ] = useState(() => {
const cartCache = JSON.parse(localStorage.getItem('cart'));
if (cartCache) {
return cartCache;
}
localStorage.setItem('cart', JSON.stringify([]));
return [];
});
这样,如果cart
中缺少localStorage
元素,则代码将使用默认的[]
空数组创建该元素,并将其设置为您的状态。在其他情况下,它将通过存储状态来设置状态。
请注意:另外,我在听cart
状态更改方面与the answer from kind user here保持一致,以使localStorage
与useEffect
保持最新。我的建议仅针对初始状态。