将 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 状态更改以使 localStorageuseEffect。我的建议只针对初始状态。