我知道有些反应,但是我陷入了一种奇怪的情况。
我有两个输入和一个按钮, 当两个输入都不为空时,应启用该按钮。 因此,我为每个输入值都使用了state属性,并且还使用了一个属性告诉我两个输入是否都具有值:
this.state = {
title: '',
time :'',
enabled : false
}
对于每个输入,我都有一个onChange来相应地设置State:
<input type="text" id="time" name="time" onChange={this.onChange.bind(this)} value={this.state.time}></input>
<input type="text" id="title" name="title" onChange={this.onChange.bind(this)} value={this.state.title}></input>
而onChange就是这样
onChange(e){
this.setState({
[e.target.id] : e.target.value,
enabled : ( (this.state.title==='' || this.state.time==='' ) ? false : true)
});
}
问题在于setState会查看先前的状态,而启用状态始终落后一步,因此,如果我先输入X,然后输入Y,则启用状态仍然为false。
我设法通过使用setTimeout并在其中添加第二行来解决它,但对我来说似乎错了。
onChange(e){
this.setState({
[e.target.id] : e.target.value,
});
setTimeout(() => {
this.setState({
enabled : ( (this.state.title==='' || this.state.time==='' ) ? false : true)
});
}, 0);
}
有更好的解决方案吗?
答案 0 :(得分:6)
首先,您无需维护已启用状态,因为它可以从其他状态值派生并可以直接在渲染中完成
onChange(e){
this.setState({
[e.target.id] : e.target.value,
});
}
render() {
const enabled = this.state.title !== "" && this.state.time !== "";
return (
<div>
<input type="text" id="time" name="time" onChange={this.onChange.bind(this)} value={this.state.time}></input>
<input type="text" id="title" name="title" onChange={this.onChange.bind(this)} value={this.state.title}></input>
<button disabled={!enabled}>Button</button>
</div>
)
}
答案 1 :(得分:4)
有更好的解决方案吗?
有3种解决方案可帮助您实现这一目标,只需选择一种
componentDidUpdate()
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
title: "",
time: "",
enabled: false
};
}
onChange(e) {
this.setState({
[e.target.id]: e.target.value
});
}
componentDidUpdate(prevProps, prevState) {
if (
prevState.time !== this.state.time ||
prevState.title !== this.state.title
) {
if (this.state.title && this.state.time) {
this.setState({ enabled: true });
} else {
this.setState({ enabled: false });
}
}
}
render() {
return (
<React.Fragment>
<input
type="text"
id="time"
name="time"
onChange={this.onChange.bind(this)}
value={this.state.time}
/>
<input
type="text"
id="title"
name="title"
onChange={this.onChange.bind(this)}
value={this.state.title}
/>
<button disabled={!this.state.enabled}>Button</button>
</React.Fragment>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
setState
回调
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
title: "",
time: "",
enabled: false
};
}
onChange(e) {
this.setState({[e.target.id]: e.target.value},
() => {
if (this.state.title && this.state.time) {
this.setState({ enabled: true });
} else {
this.setState({ enabled: false });
}
}
);
}
render() {
return (
<React.Fragment>
<input
type="text"
id="time"
name="time"
onChange={this.onChange.bind(this)}
value={this.state.time}
/>
<input
type="text"
id="title"
name="title"
onChange={this.onChange.bind(this)}
value={this.state.title}
/>
<button disabled={!this.state.enabled}>Button</button>
</React.Fragment>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
enabled
和title
计算time
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
title: "",
time: ""
};
}
onChange(e) {
this.setState({
[e.target.id]: e.target.value
});
}
render() {
const enabled = this.state.time && this.state.title;
return (
<React.Fragment>
<input
type="text"
id="time"
name="time"
onChange={this.onChange.bind(this)}
value={this.state.time}
/>
<input
type="text"
id="title"
name="title"
onChange={this.onChange.bind(this)}
value={this.state.title}
/>
<button disabled={!enabled}>Button</button>
</React.Fragment>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
答案 2 :(得分:1)
如果要在当前更改发生后设置状态,则可以将第二个参数(回调)传递给setState,这将在状态已设置并在其中再次设置状态后发生。这将导致额外的重新渲染,但这似乎正是您要的。这只是为了让您知道在当前状态更改发生后如何做...
但是,我会同意Shubham Khatri的回答。那将更加合乎逻辑。
答案 3 :(得分:1)
@Shubham Khatri给出了正确的答案(您在该州实际上不需要enabled
属性),但重要的是要了解该州的情况以及您使用hack
的原因setTimeout
工作(幸运的是,我认为如此)。
setState()并不总是立即更新组件。它可能 批处理或将更新推迟到以后。这使得阅读this.state 在调用setState()之后立即发生潜在的陷阱。相反,使用 componentDidUpdate或setState回调(setState(updater, 回调)),保证在更新后都会触发 已应用。
另外,state updates may be asynchronous:
React可以将多个setState()调用批处理为单个更新,以用于 性能。
由于this.props和this.state可能会异步更新,因此您 不应依赖于它们的值来计算下一个状态。
我希望这可以澄清您的问题。