Javascript 等效于使用React挂钩的componentDidUpdate

Javascript 等效于使用React挂钩的componentDidUpdate,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,tldr如何模拟组件diddupdate或使用带有数组的键道具强制重置组件 我正在实现一个组件,它显示一个计时器,并在达到零时执行回调。回调的目的是更新对象列表。后一个组件由新的useState和useffect组成 状态包含计时器启动时间和剩余时间的参考。效果设置每秒调用一次的间隔,以更新剩余时间,并检查是否应调用回调 该组件并不是要重新安排计时器,或者在时间间隔为零时保持时间间隔,而是应该执行回调并空闲。为了让计时器刷新,我希望将一个数组传递给键,这将导致组件的状态被重置,因此计时器将重新启

tldr如何模拟
组件diddupdate
或使用带有数组的
道具强制重置组件

我正在实现一个组件,它显示一个计时器,并在达到零时执行回调。回调的目的是更新对象列表。后一个组件由新的
useState
useffect
组成

状态
包含计时器启动时间和剩余时间的参考。
效果
设置每秒调用一次的间隔,以更新剩余时间,并检查是否应调用回调

该组件并不是要重新安排计时器,或者在时间间隔为零时保持时间间隔,而是应该执行回调并空闲。为了让计时器刷新,我希望将一个数组传递给
,这将导致组件的状态被重置,因此计时器将重新启动。不幸的是,
必须与字符串一起使用,因此我的数组的引用是否已更改不会产生任何影响

我还试图通过传递我关心的数组来推动对道具的更改,但状态保持不变,因此间隔没有重置

为了强制仅使用新的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;
尝试与道具更改一起使用:

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


listOfObjects
指的是一个对象数组,对象本身不一定会改变,因此数组应该与
进行比较==。通常,该值将来自
Redux
,其中操作
updateListFobjects
会导致数组重新初始化,如下所示:
NewListObjects=[…ListObjects]

重新装载组件的方法是提供新的
属性。它不一定是字符串,但会在内部强制为字符串,因此如果
listOfObjects
是字符串,则
key
会在内部与
listOfObjects.toString()进行比较

可以使用任意随机键,例如
uuid
Math.random()
。可以在父组件中执行
listOfObjects
的粗略比较,以提供新键
useMemo
hook可以在父状态下有条件地更新remount键,并且
listOfObjects
可以用作需要记忆的参数列表。这是一个:

constremountkey=usemo(()=>Math.random(),ListofObject);
返回(
console.log('refreshed')}key={remountKey}/>
);
作为重新安装密钥的替代方法,子组件可以重置自己的状态并公开回调以触发重置


对子组件中的
列表对象进行浅层比较将是一种反模式,因为这要求它了解父组件的实现。

简而言之,当数组的引用更改时,您希望重置计时器,对吗? 如果是这样,您将需要使用一些扩散机制,一个基于纯钩子的解决方案将利用
useffect
的第二个参数,如下所示:

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

  //reset part, lets just set startedAt to now
  useEffect(() => setStartedAt(new Date()),
    //important part
    [props.listOfObjects] // <= means: run this effect only if any variable
    // in that array is different from the last run
  )

  useEffect(() => {
    // everything with intervals, and the render
  })
}
函数刷新器(道具){
const[startedAt,setStartedAt]=useState(新日期());
const[timeRemaining,setTimeRemaining]=useState(getTimeRemaining(startedAt,props.delay));
//重置部分,让我们将startedAt设置为现在
useEffect(()=>设置开始日期(新日期()),
//重要部分
[道具列表对象]//{
//每件事都有间隔,渲染
})
}

有关此行为的更多信息,请参见此处

useRef
在功能组件中创建一个“实例变量”。它充当一个标志,指示它是否处于装载或更新阶段,而不处于更新状态

const mounted = useRef();
useEffect(() => {
  if (!mounted.current) {
    // do componentDidMount logic
    mounted.current = true;
  } else {
    // do componentDidUpdate logic
  }
});
使用自定义挂钩

export const useComponentDidUpdate=(效果、依赖项)=>{
const hasMounted=useRef(false);
使用效果(
() => {
如果(!hasMounted.current){
hasMounted.current=true;
返回;
}
效应();
}, 
依赖关系
);
};
初始渲染后,效果将不会运行。此后,它取决于应观察的值数组。如果为空,则将在每次渲染后运行。否则,它将在其中一个值发生更改时运行。

首先创建钩子

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
}
现在在主功能中

import React, {useEffect, useState} from 'react';
import {Text, View} from 'react-native';
import usePrevious from './usePrevious';

export default function Example() {
  const [count, setCount] = useState(0);
  const prevCount = usePrevious(count);
  

  useEffect(() => {
    // this one is your didupdate method for count variable
    if (count != prevCount) {
      alert('count updated')
    }
  }, [count]);



  return (
    <View>
      <Text>
        You clicked {count} times {prevCount}{' '}
      </Text>
      
      <Text onPress={() => setCount(count + 1)}>Increment</Text>

      <Text onPress={() => setCount(count - 1)}>Decrement</Text>
    </View>
  );
}
import React,{useffect,useState}来自“React”;
从“react native”导入{Text,View};
从“/usePrevious”导入usePrevious;
导出默认函数示例(){
const[count,setCount]=useState(0);
const prevCount=usePrevious(计数);
useffect(()=>{
//这是count变量的diddupdate方法
if(count!=prevCount){
警报('计数已更新')
}
},[计数];
返回(
您单击了{count}次{prevCount}{'}
setCount(计数+1)}>增量
设置计数(计数-1)}>递减
);
}

没有
组件didReceiveProps
生命周期方法。你是说组件将收到道具吗?哎呀,我收到了。事实上,我将编辑并参考
componentdiddupdate
,因为不鼓励使用
componentWillReceiveProps
。请提供。ListOfObjects到底是什么?我添加了一些关于该数组的信息,但是这个变量代表什么并不重要,只要理解它应该使用
进行肤浅的比较==。不完全是。我将很快给出答案。创建父组件来进行比较只会将我的问题推到组件之外,如何使用钩子实现比较?请注意,仅使用随机键意味着父com的任何重新呈现
function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
}
import React, {useEffect, useState} from 'react';
import {Text, View} from 'react-native';
import usePrevious from './usePrevious';

export default function Example() {
  const [count, setCount] = useState(0);
  const prevCount = usePrevious(count);
  

  useEffect(() => {
    // this one is your didupdate method for count variable
    if (count != prevCount) {
      alert('count updated')
    }
  }, [count]);



  return (
    <View>
      <Text>
        You clicked {count} times {prevCount}{' '}
      </Text>
      
      <Text onPress={() => setCount(count + 1)}>Increment</Text>

      <Text onPress={() => setCount(count - 1)}>Decrement</Text>
    </View>
  );
}