相当于使用React钩子的componentDidUpdate [英] Equivalent to componentDidUpdate using React hooks

查看:164
本文介绍了相当于使用React钩子的componentDidUpdate的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

tldr; 如何模拟 componentDidUpdate 或将 key 属性与数组一起使用以强制重置组件?>

我正在实现一个显示计时器的组件,并在该组件达到零时执行回调.目的是让回调更新对象列表.后一个组件由新的反应挂钩 useState useEffect .

状态包含对计时器启动时间和剩余时间的引用. effect 设置一个每秒调用一次的间隔,以更新剩余时间,并检查是否应调用该回调.

该组件不是要重新安排计时器的时间,也不打算在间隔达到零时保持间隔继续运行,而是应该执行回调和空闲操作.为了刷新计时器,我希望将一个数组传递给 key ,这将导致重置组件的状态,因此计时器将重新启动.不幸的是, key 必须与字符串一起使用,因此,我数组的引用是否已更改都没有效果.

我还尝试通过传递我关注的数组来对道具进行更改,但是状态得以保持,因此间隔没有重置.

观察数组中的浅层变化以强制仅使用新的hooks API来更新状态的首选方法是什么?

 从'react'导入React,{useState,useEffect};从'prop-types'导入PropTypes;函数getTimeRemaining(startedAt,delay){const now = new Date();const end = new Date(startedAt.getTime()+ delay);返回Math.max(0,end.getTime()-now.getTime());}函数RefresherTimer(props){const [startedAt,setStartedAt] = useState(new Date());const [timeRemaining,setTimeRemaining] = useState(getTimeRemaining(startedAt,props.delay));useEffect(()=> {if(timeRemaining< = 0){//组件设置为空闲,我们不设置间隔.返回;}//设置间隔,以每秒刷新一次组件.const i = setInterval(()=> {const nowRemaining = getTimeRemaining(startedAt,props.delay);setTimeRemaining(nowRemaining);如果(nowRemaining< = 0){props.callback();clearInterval(i);}},1000);return()=>{clearInterval(i);};});let message =`刷新$ {Math.ceil(timeRemaining/1000)} s.if(timeRemaining< = 0){message ='正在刷新...';}返回< div> {message}</div> ;;}RefresherTimer.propTypes = {回调:PropTypes.func.isRequired,延迟:PropTypes.number};RefresherTimer.defaultProps = {延误:2000};导出默认的RefresherTimer; 

尝试与 key 一起使用:

 < RefresherTimer delay = {20000} callback = {props.updateListOfObjects} key = {listOfObjects}/> 

尝试与道具变更一起使用:

 < RefresherTimer delay = {20000} callback = {props.updateListOfObjects} somethingThatChanges = {listOfObjects}/> 

listOfObjects 是指对象数组,其中对象本身不一定会更改,因此应将该数组与!== 进行比较.通常,该值将来自 Redux ,其中操作 updateListOfObjects 导致数组重新初始化,如下所示: newListOfObjects = [... listOfObjects] .

解决方案

useRef 创建一个实例变量".在功能组件中.它用作标志,指示它是处于挂载阶段还是处于更新阶段而不处于更新状态.

  const Mount = useRef();useEffect(()=> {如果(!mount.current){//执行componentDidMount逻辑mount.current = true;} 别的 {//执行componentDidUpdate逻辑}}); 

tldr; How do I simulate componentDidUpdate or otherwise use the key prop with an array to force my component to be reset?

I'm implementing a component which displays a timer and executes a callback when it reaches zero. The intent is for the callback to update a list of objects. The latter component is made of the new React hooks useState and useEffect.

The state contains a reference to the time at which the timer was started, and the time remaining. The effect sets an interval called every second to update the time remaining, and to check whether the callback should be called.

The component is not meant to reschedule a timer, or keep the interval going when it reaches zero, it's supposed to execute the callback and idle. In order for the timer to refresh, I was hoping to pass an array to key which would cause the component's state to be reset, and thus the timer would restart. Unfortunately key must be used with a string, and therefore whether or not my array's reference has changed produces no effect.

I also tried to push changes to the props by passing the array that I was concerned about, but the state was maintained and thus the interval was not reset.

What would be the preferred method to observe shallow changes in an array in order to force a state to be updated solely using the new hooks API?

import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';

function getTimeRemaining(startedAt, delay) {
    const now = new Date();
    const end = new Date(startedAt.getTime() + delay);
    return Math.max(0, end.getTime() - now.getTime());
}

function RefresherTimer(props) {
    const [startedAt, setStartedAt] = useState(new Date());
    const [timeRemaining, setTimeRemaining] = useState(getTimeRemaining(startedAt, props.delay));

    useEffect(() => {

        if (timeRemaining <= 0) {
            // The component is set to idle, we do not set the interval.
            return;
        }

        // Set the interval to refresh the component every second.
        const i = setInterval(() => {
            const nowRemaining = getTimeRemaining(startedAt, props.delay);
            setTimeRemaining(nowRemaining);

            if (nowRemaining <= 0) {
                props.callback();
                clearInterval(i);
            }
        }, 1000);

        return () => {
            clearInterval(i);
        };
    });

    let message = `Refreshing in ${Math.ceil(timeRemaining / 1000)}s.`;
    if (timeRemaining <= 0) {
        message = 'Refreshing now...';
    }

    return <div>{message}</div>;
}

RefresherTimer.propTypes = {
    callback: PropTypes.func.isRequired,
    delay: PropTypes.number
};

RefresherTimer.defaultProps = {
    delay: 2000
};

export default RefresherTimer;

Attempted to use with key:

<RefresherTimer delay={20000} callback={props.updateListOfObjects} key={listOfObjects} />

Attempted to use with a props change:

<RefresherTimer delay={20000} callback={props.updateListOfObjects} somethingThatChanges={listOfObjects} />

listOfObjects refers to an array of objects, where the objects themselves won't necessarily change, so the array should be compared with !==. Typically, the value will be coming from Redux, where the action updateListOfObjects causes the array to be reinitialised like so: newListOfObjects = [...listOfObjects].

解决方案

The useRef creates an "instance variable" in functional component. It acts as a flag to indicate whether it is in mount or update phase without updating state.

const mounted = useRef();
useEffect(() => {
  if (!mounted.current) {
    // do componentDidMount logic
    mounted.current = true;
  } else {
    // do componentDidUpdate logic
  }
});

这篇关于相当于使用React钩子的componentDidUpdate的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆