解决方案#1(带钥匙并重新安装):
您可能需要根据传入的 prop: 为每个外部 props 更新提供一个密钥,从而使当前组件重新安装在每个外部 props 上currentLevel
。它看起来像:
class Wrapper ... {
...
render() {
const { currentLevel } = this.props;
return (
<NameEditor key={currentLevel} {...currentLevel} />
)
}
}
export default Wrapper
...并通过告诉它对您的组件进行一些额外的更改以阻止派生的道具替换 - 它是否是第一次渲染(因为我们计划state
仅从内部控制它,并且仅通过重新安装从外部控制它,当它真的如此时) :
import PropTypes from 'prop-types'
import React from 'react'
export class NameEditor extends React.Component {
static propTypes = {
currentLevel: PropTypes.number
}
static defaultProps = {
currentLevel: 0
}
constructor(props) {
super(props)
this.state = {
currentLevel: 0,
isFirstRender: false
}
}
static getDerivedStateFromProps(nextProps, prevProps) {
if (!prevProsp.isFirstRender) {
return {
currentLevel: nextProps.currentLevel,
isFirstRender: true
};
}
return null;
}
_handleInputChange = e => {
this.setState({
currentLevel: e.target.value
})
}
render() {
const { currentLevel } = this.state
return (
<input
placeholder={0}
value={currentLevel}
onChange={this._handleInputChange}
/>
)
}
}
export default NameEditor
因此,在这种情况下,您将有机会通过手动输入表单中的值来操纵组件状态。
解决方案#2(不按标志重新挂载):
尝试设置一些标志来分隔每次重新渲染时的外部 (getDerived...) 和内部 (Controlled Comp...) 状态更新。例如updateType
:
import PropTypes from 'prop-types'
import React from 'react'
export class NameEditor extends React.Component {
static propTypes = {
currentLevel: PropTypes.number
}
static defaultProps = {
currentLevel: 0
}
constructor(props) {
super(props)
this.state = {
currentLevel: 0,
updateType: 'props' // by default we expecting update by incoming props
}
}
static getDerivedStateFromProps(nextProps, prevProps) {
if (!prevState.updateType || prevState.updateType === 'props') {
return {
updateType: 'props',
currentLevel: nextProps.currentLevel,
exp: nextProps.exp
}
}
if (prevState.updateType === 'state') {
return {
updateType: '' // reset flag to allow update from incoming props
}
}
return null
}
_handleInputChange = e => {
this.setState({
currentLevel: e.target.value
})
}
render() {
const { currentLevel } = this.state
return (
<input
placeholder={0}
value={currentLevel}
onChange={this._handleInputChange}
/>
)
}
}
export default NameEditor
PS这可能是一种反模式(希望丹永远不会看到这一点),但我现在无法在我的脑海中找到更好的解决方案。
解决方案#3:
请参阅Sultan H.这篇文章下的帖子,关于带有来自包装器组件的显式回调的受控逻辑。