【问题标题】:Converting componentDidMount into useEffect将 componentDidMount 转换为 useEffect
【发布时间】:2021-01-31 18:16:30
【问题描述】:

我正在尝试学习 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>
    )
  }
}*/

【问题讨论】:

    标签: javascript reactjs react-hooks use-effect react-component


    【解决方案1】:

    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]);
    

    【讨论】:

    • 我同意useEffect 对您的问题的监听更改部分,这就是我赞成这个答案的原因。您能否检查一下我的回答here,您对在useState 中设置初始状态有何看法,而不是使用useEffect。谢谢!
    • const cartLocalCache = JSON.parse(localStorage.getItem('cart')) || []; const [ cart, setCart ] = useState(cartLocalCache); 和 useEffect 使用 @kind 用户的推荐来监听购物车变化?
    • @AJSwift 很酷,你也可以这样做setCart(cartCache || [])
    • @kinduser 这是一个很好的组合,我相信建议的答案。
    • 谢谢你,很好的答案
    【解决方案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 [];
    });
    

    这样,如果localStorage 中缺少cart 元素,代码将使用默认的[] 空数组创建它,并将其设置为您的状态。其他情况下,它会将您的状态设置为存储中的值。

    请注意:我也同意the answer from kind user here 的收听cart 状态更改以使localStorageuseEffect 保持同步。我的建议只针对初始状态。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-08
      • 2021-01-26
      • 2020-10-15
      • 2021-01-10
      • 1970-01-01
      • 1970-01-01
      • 2020-02-12
      • 2021-03-02
      相关资源
      最近更新 更多