我有一个受控输入,该输入接受名为user
的道具。该对象由其父组件传递给它,在此它用观察者 1 异步初始化。
在父组件中:
onAuthStateChanged() {
this.unregisterAuthObserver = onAuthStateChanged((user) => {
this.setState({
isSignedIn: Boolean(user),
user,
});
});
}
我想用user.displayName
填充受控输入的初始状态。如下所示,它不应该是反模式的,因为状态仅取决于构造中的道具user
。
class ControlledInput extends Component {
constructor(props) {
super(props);
const { user } = props;
this.state = {
displayName: user ? user.displayName : '',
};
}
}
当我刷新受控输入时,会出现以下问题:
user
的值为undefined
。构造了组件,并将displayName
分配给''
。user
被分配了一个复杂对象,React重新渲染了该组件。这不会更改组件的状态,并且displayName
仍然是''
。 我坚持如何利用组件生命周期方法来实现这一目标。这种情况下有最佳实践吗?我应该依赖异步道具还是将观察者移动到受控组件中?
我已经考虑过使用componentDidUpdate()
来确定何时分配user
,但这感觉就像是在被黑客入侵。
使用此机会在组件更新后在DOM上进行操作。只要您将当前的道具与以前的道具进行比较,这也是一个进行网络请求的好地方(例如,如果道具未更改,则可能不需要网络请求)。
1 观察者是Firebase身份验证的一部分,但我不确定这与问题是否相关。
答案 0 :(得分:0)
无需在构造函数中进行分配。您应该使用提供给render方法的道具,并遵循Lifting State Up pattern处理对父代状态的更新。然后,它将向下流到子组件。
请参见下面的示例。 “增量”按钮模拟异步调用。 ControlledInput
是只读显示,而ControlledInput2
允许对状态中反映的输入进行编辑。
class Parent extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.onInputChanged = this.onInputChanged.bind(this);
this.state = {
user,
count: 1
};
}
handleClick(e) {
const { user, count } = this.state;
this.setState({
user: { ...user, displayName: `display ${count + 1}` },
count: count + 1
});
}
onInputChanged(name) {
this.setState({
user: Object.assign(user, { displayName: name })
});
}
render() {
const { user, count } = this.state;
return (
<div>
<ControlledInput user={user} />
<div>{user.displayName}</div>
<div>Count: {count}</div>
<button onClick={this.handleClick}>increment</button>
<div>
<ControlledInput2 onInputChanged={this.onInputChanged} user={user} />
</div>
</div>
);
}
}
const ControlledInput = ({ user }) =>
<input type="text" value={user.displayName} />;
class ControlledInput2 extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.onInputChanged(e.target.value);
}
render() {
const { user } = this.props;
return (
<input
type="text"
onChange={this.handleChange}
value={user.displayName}
/>
);
}
}
const user = { displayName: undefined };
const props = { user };
const rootElement = document.getElementById("sample");
ReactDOM.render(<Parent {...props} />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.2/umd/react-dom.production.min.js"></script>
<div id="sample"></div>