简体   繁体   English

我如何使用 useEffect 替换 componentDidMount?

[英]how could i use useEffect to replace componentDidMount?

I would like to use useEffect() to instead of componentWillMount() , but I found the hook can not use in class components, so I change the code as Function component, but it will get more error for the whole component, all code with this.xxx are getting an error, how could I edit below code to make it work?我想使用useEffect()来代替componentWillMount() ,但我发现钩子不能在类组件中使用,所以我将代码更改为 Function 组件,但它会为整个组件带来更多错误,所有代码都带有this.xxx 出现错误,我如何编辑下面的代码以使其正常工作? Please help me.请帮我。 Below code is working fine with componentWillMount() .下面的代码与componentWillMount()一起工作正常。

import React, { Component } from 'react';
import './index.less';
import { formateDate } from '../../utils/dateUtils';
import memoryUtils from '../../utils/memoryUtils';
import { reqWeather } from '../../api/index';
import { withRouter } from 'react-router-dom';
import menuList from '../../config/menuConfig';

class Header extends Component {
  state = {
    currentTime: formateDate(Date.now()),
    dayPictureUrl: '',
    weather: '',
  };
  getTime = () => {
    setInterval(() => {
      const currentTime = formateDate(Date.now());
      this.setState({ currentTime });
    }, 1000);
  };
  getWeather = async () => {
    const { dayPictureUrl, weather } = await reqWeather('Auckland');
    this.setState({ dayPictureUrl, weather });
  };
  getTitle = (props) => { 
    const path = this.props.location.pathname;
    let title;
    menuList.forEach(item => {
      if (item.key === path) {
        title = item.title;
      } else if (item.children) {
        const cItem = item.children.find(cItem => cItem.key === path);
        if (cItem) {
          title = cItem.title;
        }
      }
    });
    return title;
  };
  componentDidMount() {
    this.getTime();
    this.getWeather();
  }
  render() {
    const { currentTime, dayPictureUrl, weather } = this.state;
    const username = memoryUtils.user.username;
    const title = this.getTitle();
    return (
      <div className="header">
        <div className="header-top">
          <span>Welcome, {username}</span>
          <a href>logout</a>
        </div>
        <div className="header-bottom">
          <div className="header-bottom-left">{title}</div>
          <div className="header-bottom-right">
            <span>{currentTime}</span>
            <img src={dayPictureUrl} alt="weather" />
            <span>{weather}</span>
          </div>
        </div>
      </div>
    );
  }
}
export default withRouter(Header)

I've converted from react classes to react hooks I hope it help, I haven't tested because I don't have the external files that you have but I hope it helps otherwise just comment on this solution ;)我已经从反应类转换为反应钩子我希望它有帮助,我没有测试,因为我没有你拥有的外部文件,但我希望它有帮助,否则只是对这个解决方案发表评论;)

import React, { useState, useEffect } from 'react';
import './index.less';
import { formateDate } from '../../utils/dateUtils';
import memoryUtils from '../../utils/memoryUtils';
import { reqWeather } from '../../api/index';
import { withRouter, useLocation } from 'react-router-dom';
import menuList from '../../config/menuConfig';



function Header(){
const [currentTime, setCurrentTime] = useState(formateDate(Date.now()))
const [dayPictureUrl, setDayPictureUrl] = useState('')
const [weather, setWeather] = useState('')
const location = useLocation();
const path = location.pathname;

useEffect(() => {
    getTime();
    getWeather();
},[]);


const getTime = () => {
    setInterval(() => {
      const currentTime = formateDate(Date.now());
      setCurrentTime(currentTime)
    }, 1000);
  };
const   getWeather = async () => {
    const { dayPictureUrl, weather } = await reqWeather('Auckland');
    setDayPictureUrl(dayPictureUrl)
    setWeather(weather)

  };
const  getTitle = (props) => { 
    let title;
    menuList.forEach(item => {
      if (item.key === path) {
        title = item.title;
      } else if (item.children) {
        const cItem = item.children.find(cItem => cItem.key === path);
        if (cItem) {
          title = cItem.title;
        }
      }
    });
    return title;
  };
  const username = memoryUtils.user.username;
  const title = getTitle();
  return (<div className="header">
  <div className="header-top">
    <span>Welcome, {username}</span>
    <a href>logout</a>
  </div>
  <div className="header-bottom">
    <div className="header-bottom-left">{title}</div>
    <div className="header-bottom-right">
      <span>{currentTime}</span>
      <img src={dayPictureUrl} alt="weather" />
      <span>{weather}</span>
    </div>
  </div>
</div>  )
}


export default Header

Here's my go at converting the function to using hooks.这是我将函数转换为使用钩子的方法。

One of the best things about hooks is that they can all be called as many times as you like, which allows us to separate the concerns of a component into logical blocks.关于钩子的最好的事情之一是它们都可以根据需要多次调用,这允许我们将组件的关注点分离为逻辑块。

useEffect shouldn't be considered a direct replacement for componentDidMount as it works differently. useEffect不应被视为 componentDidMount 的直接替代品,因为它的工作方式不同。 The closest would actually be useLayoutEffect because of the timing of it matches componentDidMount and componentdDidUpdate .最接近的实际上是useLayoutEffect因为它匹配componentDidMountcomponentdDidUpdate More detail on the difference between the two: useEffect vs useLayoutEffect .关于两者区别的更多细节: useEffect 与 useLayoutEffect Although you should in general use useEffect primarily.虽然您通常应该主要使用useEffect

Getting used to hooks requires a bit of a shift in how you think of components, but in my opinion, it's worth the effort to switch!习惯 hooks 需要稍微改变您对组件的看法,但在我看来,转换的努力是值得的!

import React, {useEffect, useMemo, useState} from 'react';
import './index.less';
import { formateDate } from '../../utils/dateUtils';
import memoryUtils from '../../utils/memoryUtils';
import { reqWeather } from '../../api/index';
import { useLocation } from 'react-router-dom';
import menuList from '../../config/menuConfig';

export default function Header (props){
  const [currentTime, setCurrentTime] = useState(formateDate(Date.now()));
  useEffect(()=>{
    const intervalId = setInterval(()=>{
      setCurrentTime(formateDate(Date.now()));
    },1000)
    // Make sure to cleanup your effects!
    return ()=>{clearInterval(intervalId)}
  },[])

  const [dayPictureUrl, setDayPictureUrl] = useState('');
  const [weather, setWeather] = useState('');
  useEffect(() => {
    const getWeather = async () => {
      const { dayPictureUrl, weather } = await reqWeather('auckland');
      setDayPictureUrl(dayPictureUrl);
      setWeather(weather);
    };
    // Assuming that we want to have the weather dynamically based on a passed in prop (i.e. props.city), or a state.
    getWeather();
  }, []);

  // useLocation gets the location via a hook from react router dom
  const location = useLocation();
  const title = useMemo(()=>{
    // useMemo as this can be an expensive calculation depending on the length of menuList
    // menuList is always a constant value, so it won't change
    const path = location.pathname;
    let title;
    menuList.forEach(item => {
      if (item.key === path) {
        title = item.title;
      } else if (item.children) {
        const cItem = item.children.find(cItem => cItem.key === path);
        if (cItem) {
          title = cItem.title;
        }
      }
    });
    return title;
  },[location.pathname])
  
  const username = memoryUtils.user.username;

  return (
    <div className="header">
      <div className="header-top">
        <span>Welcome, {username}</span>
        <a href>logout</a>
      </div>
      <div className="header-bottom">
        <div className="header-bottom-left">{title}</div>
        <div className="header-bottom-right">
          <span>{currentTime}</span>
          <img src={dayPictureUrl} alt="weather" />
          <span>{weather}</span>
        </div>
      </div>
    </div>
  );
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM