对于我来说,究竟componentWillReceiveProps和getDerivedStateFromProps到底是什么是微妙的问题。因为,我在使用getDerivedStateFromProps时遇到了一个问题:
// Component
state = {
myState: []
}
// Using this method works fine:
componentWillReceiveProps(nextProps) {
this.setState({
myState: nextProps.myPropsState
})
}
// But using this method will cause the checkboxes to be readonly:
static getDerivedStateFromProps(nextProps,prevProps) {
const { myPropsState: myState } = nextProps
return {
myState
}
}
// And here's checkbox
<input type="checkbox" id={`someid`}
onChange={(e) => this.handleMethod(e, comp.myState)}
checked={myState.indexOf(comp.myState) > -1} />
反应版本:16.4.1
答案 0 :(得分:4)
getDerivedStateFromProps
并不是componentWillReceiveProps
的直接替代,纯粹是因为它在每次更新后都会被调用,无论是状态更改还是道具更改或父级重新呈现。 / p>
无论如何,仅从getDerivedStateFromProps
返回状态是不正确的方法,您需要在返回值之前比较状态和props。否则,每次更新都会将状态重置为道具,并且循环会继续
按照 docs
getDerivedStateFromProps
在调用渲染之前被调用 初始安装和后续更新上的方法。这应该 返回对象以更新状态,或返回null
不更新任何内容。此方法适用于状态取决于以下情况的罕见用例 道具随时间变化。例如,它可能对 实现一个
<Transition>
组件,将其先前的和 下一个孩子决定要对其中的一个进行动画处理。派生状态导致冗长的代码并使您的组件 很难考虑。确保您熟悉更简单 替代方案:
如果您需要执行副作用(例如,数据获取 或动画)以响应道具更改, 改为
componentDidUpdate
生命周期。如果您只想在道具更改时重新计算一些数据,请使用 而是
memoization
助手。如果您想在道具更改时“重置”某些状态,请考虑 制作组件
fully controlled
或fully uncontrolled with a key instead
。
PS 。请注意,getDerivedStateFromProps的参数是props
和state
,而不是nextProps and
prevProps`
要了解更多详细信息,
为了根据道具更改进行更改,我们需要将prevPropsState存储在状态中,以便检测更改。一个典型的实现看起来像
static getDerivedStateFromProps(props, state) {
// Note we need to store prevPropsState to detect changes.
if (
props.myPropsState !== state.prevPropsState
) {
return {
prevPropsState: state.myState,
myState: props.myPropsState
};
}
return null;
}
答案 1 :(得分:0)
从react docs:
请注意,无论原因如何,都会在每个渲染器上触发该方法。这与
UNSAFE_componentWillReceiveProps
相反,setState
仅在父级导致重新渲染时才触发,而不是由于本地setState()
而触发。
每次调用(e) => this.handleMethod(e, comp.myState)
后,您实际上都在用当前道具覆盖状态。因此,当您选中一个框setState()
时,即假设调用getDerivedStateFromProps()
以更新该复选框的选中状态。但是之后,(function(){
'use strict';
angular.module('sampleapp')
.factory('Base64', function () {
var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
return {
encode: function (input) {
var output = "";
var chr1, chr2, chr3 = "";
var enc1, enc2, enc3, enc4 = "";
var i = 0;
do {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
keyStr.charAt(enc1) +
keyStr.charAt(enc2) +
keyStr.charAt(enc3) +
keyStr.charAt(enc4);
chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
return output;
},
decode: function (input) {
var output = "";
var chr1, chr2, chr3 = "";
var enc1, enc2, enc3, enc4 = "";
var i = 0;
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
var base64test = /[^A-Za-z0-9\+\/\=]/g;
if (base64test.exec(input)) {
window.alert("There were invalid base64 characters in the input text.\n" +
"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
"Expect errors in decoding.");
}
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
do {
enc1 = keyStr.indexOf(input.charAt(i++));
enc2 = keyStr.indexOf(input.charAt(i++));
enc3 = keyStr.indexOf(input.charAt(i++));
enc4 = keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
return output;
}
};
});
})();
将被调用(渲染前),以还原该更改。这就是unconditionally updating state from props is considered an anti-pattern的原因。
答案 2 :(得分:0)
最后,我解决了我的问题。这是一个痛苦的调试过程:
// Child Component
// instead of this
// this.props.onMyDisptach([...myPropsState])
// dispatching true value since myPropsState contains only numbers
this.props.onMyDispatch([...myPropsState, true])
这是因为,我有两个条件:1)复选框更改(组件)2)按下重置按钮(子组件)
按下重置按钮时,我需要重置状态。因此,在将状态分配给props for reset按钮时,我使用了一个布尔值来知道这是对reset的更改。您可以使用任何喜欢的东西,但需要对其进行跟踪。
现在,在组件的此处,在调试控制台输出后,我发现了一些关于componentWillReceiveProps和getDerivedStateFromProps之间差异的提示。
// Component
static getDerivedStateFromProps(props, state) {
const { myPropsState: myState } = props
// if reset button is pressed
const true_myState = myState.some(id=>id===true)
// need to remove true value in the store
const filtered_myState = myState.filter(id=>id!==true)
if(true_myState) {
// we need to dispatch the changes to apply on its child component
// before we return the correct state
props.onMyDispatch([...filtered_myState])
return {
myState: filtered_myState
}
}
// obviously, we need to return null if no condition matches
return null
}
这是我发现控制台输出结果的地方:
getDerivedStateFromProps每当道具更改时立即记录
componentWillReceiveProps仅在子传播道具更改后记录日志
getDerivedStateFromProps不响应道具更改(我的意思是如示例代码中的调度更改)
componentWillReceiveProps响应道具更改
因此,我们需要在使用getDerivedStateFromProps时向子组件提供更改。
在我需要的状态下粘贴真实值的过程,因为与componentWillReceiveProps不同,getDerivedStateFromProps处理所有更改,而componentWillReceiveProps仅处理子组件将更改分发给道具。
顺便说一句,您可以使用自定义属性来检查它是否已更改,并在getDerivedStateFromProps中更新其值,但是由于某些原因,我必须对该技术进行调整。
我的措词可能有些混乱,但希望您能理解。