36

React 引入了新的静态方法getDerivedStateFromProps(props, state),该方法在每个渲染方法之前调用,但为什么呢?在道具更改后调用它对我来说很有意义,但在setState它没有意义之后,也许我错过了一些东西。

我正在根据我的公司要求创建一个datePicker组件,组件日期由道具控制。我在组件中有以下状态。

selectedDate: number;
selectedMonth: number;
selectedYear: number;
currentMonth: number;
currentYear: number;
view: string;

selected 表示从 date 属性派生的选定日期,currentMonthcurrentYear表示当前日历视图中的月份和年份。

如果datefrom prop 发生变化,selected*则应相应更改。为此,我正在使用但假设用户单击月份名称,这会将日历视图切换为月份(而不是显示月份的日期名称),该函数使用 setState 对此进行更新,但日期属性与之前(包含上个月)应该被调用,并且 currentMonth 再次与之前相同,而不是改变。currentMonthcurrentYeargetDerivedStateFromPropscurrentMonthgetDerivedStateFromProps

是的,我创建了一个额外的变量state来跟踪是否getDerivedStateFromProps被调用,setState但我认为这不是正确的方法。

要么我做错了什么,要么遗漏了什么,要么getDerivedStateFromProps不应该被调用setState。可能我做错了什么。

4

6 回答 6

10

我做了这样的事情

constructor(props) {
    super(props);
    this.state = {
        expanded: props.expanded,
        ownUpdate: false
    }
}

static getDerivedStateFromProps(props, state) {
    if (state.ownUpdate) {
        return {
            expanded: state.expanded,
            ownUpdate: false
        };
    } else if (props.expanded !== state.expanded) {
        return {
            expanded: props.expanded
        };
    }
    return null;
}

toggle() {
    this.props.onAftePress(this.state.expanded, this.props.index);
    this.setState({
        expanded: !this.state.expanded,
        ownUpdate: true
    })
}
于 2019-07-25T18:19:26.937 回答
10

getDerivedStateFromProps每当接收到新的 propssetStateforceUpdate时,hook的工作方式。

在 的版本中,无论何时使用16.3React 都不会影响。但是他们在以 开头的版本中对其进行了改进 ,因此每当调用时,都会被钩住。getDerivedStateFromPropssetState16.4setStategetDerivedStateFromProps

这是从React 生命周期图中提取的图像:

16.3

在此处输入图像描述

^16.4

在此处输入图像描述


因此,何时getDerivedStateFromProps通过正确检查道具和状态来挂钩取决于您。这是一个例子:

static getDerivedStateFromProps (props, state) {
  // check your condition when it should run?
  if(props.currentMonth != state.currentMonth) {
    return {
      currentMonth: state.currentMonth
    }
  }
  // otherwise, don't do anything
  else {
   return null
  }
}
于 2019-03-17T03:53:24.933 回答
3

我也遇到了这个问题。所以我设置了另一个变量来检查第一次收到的道具。

this.state={flag:true}

getderivedstatefromprops

static getderivedstatefromprops(props, state){
   if(props.<*propName*> && flag){
      return({ props.<*propName*>, flag:false})
   }
}

如果你想使用多个 props 值,你需要相应地设置你的 if 语句(或任何其他逻辑)。

于 2019-01-06T08:02:47.237 回答
0

你的问题本身就有答案。“在每个渲染方法之前调用”。每当您执行此操作时,都会调用setState该方法。render

我建议您将状态变量提升到父组件,currentMonth并将currentYear它们与其他三个一起作为道具传递。您还可以将更改处理程序作为道具传递并从孩子那里调用它。

在初始render- currentMonth并且currentYear可以设置为null,以便您可以拥有显示默认内容的逻辑。当有人在月份名称上小鸡时,您可以调用changeHandlerfrom parent 它将传递新的道具。现在getderivedstatefromprops你不再有currentMonth并且currentYear作为`null,所以你知道月份已经改变了。

于 2019-01-22T07:53:04.357 回答
0

下面的内容似乎对我很有效,而且很笼统。

在构造函数中:

this.state = {
    props,
    // other stuff
}

在 gDSFP 中:

static getDerivedStateFromProps(newProps, state) {
    if (state.props !== newProps)
        // Compute and return new state relevant to property change
    else
        return state;
}

一些实验证实“状态”不再自动是旧状态,而是在这个钩子实例中是结合现有道具的新设置状态。我想添加钩子是为了不必直接调用 gDSFP 来重复依赖于道具的复杂状态演变,例如

this.setState(ClassName.getDerivedStateFromProps(this.props, newState))

问题是这不是一个重大的改变,但如果旧代码在 getDerivedStateFromProps 中不必要地进行大量计算,可能会导致微妙的低效率。例如,我刚刚发现一个复杂的对象正在被三次构造,一次是真实的,另外两次只是因为这个新的钩子。

于 2021-07-07T23:43:46.900 回答
0

对于这种情况(根据道具更改更新状态),请使用:

componentDidUpdate(prevProps) {
  // don't forget to compare props
  if (this.props.userID !== prevProps.userID) {
    this.fetchData(this.props.userID);
  }
}

componentDidUpdate每次更新后都会被调用(由于道具更改/状态更改)。所以你应该检查道具是否改变了(通过this.props.userID !== prevProps.userID)。

于 2020-08-03T21:38:34.247 回答