将 componentDidMount 转换为 useEffect
Converting componentDidMount into useEffect
我正在尝试学习 React hooks,并尝试将现有代码库转换为使用 hooks,但我很困惑。
useEffect
里面设置state正常吗?如果我这样做会导致可怕的无限循环吗?
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} />;
}
我原来的 class 基于组件:
/*
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>
)
}
}*/
在useEffect
中设置状态是可以的,只要你不监听依赖数组中相同字段的变化。在您的特定情况下,您只调用 useEffect
一次(因为您传递了一个空的依赖项数组)。
useEffect(() => {
const cartCache = JSON.parse(localStorage.getItem('cart'));
if (cartCache) {
setCart(cartCache);
}
}, []);
添加第二个 useEffect
以收听 cart
更改并保持 localStorage
up-to-date.
也很酷
useEffect(() => {
localStorage.setItem('cart', JSON.stringify(cart));
}, [cart]);
因为 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 [];
});
这样,如果 localStorage
中缺少 cart
元素,代码将使用默认的 []
空数组创建它,并将其设置为您的状态。其他情况下,它会将您的状态设置为存储中的值。
请注意:此外,我同意 的收听 cart
状态更改以使 localStorage
与 useEffect
。我的建议只针对初始状态。
我正在尝试学习 React hooks,并尝试将现有代码库转换为使用 hooks,但我很困惑。
useEffect
里面设置state正常吗?如果我这样做会导致可怕的无限循环吗?
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} />;
}
我原来的 class 基于组件:
/*
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>
)
}
}*/
在useEffect
中设置状态是可以的,只要你不监听依赖数组中相同字段的变化。在您的特定情况下,您只调用 useEffect
一次(因为您传递了一个空的依赖项数组)。
useEffect(() => {
const cartCache = JSON.parse(localStorage.getItem('cart'));
if (cartCache) {
setCart(cartCache);
}
}, []);
添加第二个 useEffect
以收听 cart
更改并保持 localStorage
up-to-date.
useEffect(() => {
localStorage.setItem('cart', JSON.stringify(cart));
}, [cart]);
因为 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 [];
});
这样,如果 localStorage
中缺少 cart
元素,代码将使用默认的 []
空数组创建它,并将其设置为您的状态。其他情况下,它会将您的状态设置为存储中的值。
请注意:此外,我同意 cart
状态更改以使 localStorage
与 useEffect
。我的建议只针对初始状态。