当 React 中的状态更新时 Props 不会更新
Props don't update when state updates in React
我将 App 组件中的一些值作为道具传递给 GetWordContainer 组件。使用这些道具,我可以在我的子组件中设置状态。但是,GetWordContainer 中的状态只更新一次。当App.js中的状态发生变化时,如何让子组件中的状态继续更新?
App.js
class App extends Component {
state = {
redirect: {},
word: '',
error: '',
info: [],
partOfSpeech: [],
versions: [],
shortdef: "",
pronunciation: "",
}
setRedirect = redirect =>{{
this.setState({redirect})
}
// console.log(this.state.redirect);
console.log(this.state.word);
}
handleUpdate = values =>
this.setState({...values})
render() {
return (
<>
<Route
render={ routeProps => <Redirector redirect={this.state.redirect} setRedirect={this.setRedirect} {...routeProps} />}
/>
<header>
<nav>
<Link to='/'>My Dictionary</Link>
</nav>
</header>
<main>
<Route
render = { routeProps =>
!routeProps.location.state?.alert ? '' :
<div>
{ routeProps.location.state.alert }
</div>
}
/>
<Switch>
<Route exact path="/" render={ routeProps =>
<Home
setRedirect={this.setRedirect}
handleUpdate={this.handleUpdate}
{...routeProps} />}
/>
<Route exact path="/definition/:word" render={routeProps =>
<GetWordContainer
setRedirect={this.setRedirect}
handleUpdate={this.handleUpdate}
word={this.state.word}
partOfSpeech={this.state.partOfSpeech}
versions={this.state.versions}
shortdef={this.state.shortdef}
pronunciation={this.state.pronunciation}
{...routeProps} />}
/>
</Switch>
</main>
</>
);
}
}
GetWordContainer.js
class GetWordContainer extends Component {
//this state only updates once
state = {
word: this.props.word,
info: this.props.info,
partOfSpeech: this.props.parOfSpeech,
versions: this.props.versions,
shortdef: this.props.shortdef,
pronunciation: this.props.pronunciation,
}
render (){
return (
<div>
<Search
handleUpdate={this.props.handleUpdate}
setRedirect={this.props.setRedirect}
/>
<div>
{this.state.word}
</div>
<div>
{this.state.partOfSpeech}
</div>
<div>
{this.state.versions.map((v, i) => <div key={i}>{v}</div>)}
</div>
<div>
{this.state.pronunciation}
</div>
<div>
{this.state.shortdef}
</div>
</div>
);
}
}
您面临的问题是 GetWordContainer
组件中的 state
值是在初始渲染时实例化的。有例外,但总的来说,React 会尽可能地在渲染中重用相同的组件。这意味着该组件不会重新实例化,因此 state
值不会在重新呈现时发生变化。
这个问题的一个解决方案是使用适当的生命周期方法来处理组件何时重新渲染并适当地更新状态:getDerivedStateFromProps
但是,由于您似乎想直接渲染道具,我建议在 GetWordContainer
.
中完全避免状态
例如:
class GetWordContainer extends Component {
render() {
return (
<div>
<Search
handleUpdate={this.props.handleUpdate}
setRedirect={this.props.setRedirect}
/>
<div>{this.props.word}</div>
<div>{this.props.partOfSpeech}</div>
<div>
{this.props.versions.map((v, i) => (
<div key={i}>{v}</div>
))}
</div>
<div>{this.props.pronunciation}</div>
<div>{this.props.shortdef}</div>
</div>
);
}
}
您的构造函数生命周期方法仅运行一次 - 在组件初始化期间。如果您期望来自 parent 组件的新数据,您可以使用 componentDidUpdate()
或 getDerivedStateFromProps
.
re-render 您的 child
componentDidUpdate(prevProps) {
if (prevProps.word || this.props.word) {
this.setState({
word
})
}
}
我注意到您的 child 组件没有操纵道具,它只是一个 display-only 容器。为什么不直接传递道具直接展示而不是走最长的路呢?您的 child 组件可以是功能组件:
const GetWordContainer = (props) => {
return (
<div>
<Search
handleUpdate={props.handleUpdate}
setRedirect={props.setRedirect}
/>
<div>
{props.word}
</div>
<div>
{props.partOfSpeech}
</div>
<div>
{props.versions.map((v, i) => <div key={i}>{v}</div>)}
</div>
<div>
{props.pronunciation}
</div>
<div>
{props.shortdef}
</div>
</div>
);
}
我将 App 组件中的一些值作为道具传递给 GetWordContainer 组件。使用这些道具,我可以在我的子组件中设置状态。但是,GetWordContainer 中的状态只更新一次。当App.js中的状态发生变化时,如何让子组件中的状态继续更新?
App.js
class App extends Component {
state = {
redirect: {},
word: '',
error: '',
info: [],
partOfSpeech: [],
versions: [],
shortdef: "",
pronunciation: "",
}
setRedirect = redirect =>{{
this.setState({redirect})
}
// console.log(this.state.redirect);
console.log(this.state.word);
}
handleUpdate = values =>
this.setState({...values})
render() {
return (
<>
<Route
render={ routeProps => <Redirector redirect={this.state.redirect} setRedirect={this.setRedirect} {...routeProps} />}
/>
<header>
<nav>
<Link to='/'>My Dictionary</Link>
</nav>
</header>
<main>
<Route
render = { routeProps =>
!routeProps.location.state?.alert ? '' :
<div>
{ routeProps.location.state.alert }
</div>
}
/>
<Switch>
<Route exact path="/" render={ routeProps =>
<Home
setRedirect={this.setRedirect}
handleUpdate={this.handleUpdate}
{...routeProps} />}
/>
<Route exact path="/definition/:word" render={routeProps =>
<GetWordContainer
setRedirect={this.setRedirect}
handleUpdate={this.handleUpdate}
word={this.state.word}
partOfSpeech={this.state.partOfSpeech}
versions={this.state.versions}
shortdef={this.state.shortdef}
pronunciation={this.state.pronunciation}
{...routeProps} />}
/>
</Switch>
</main>
</>
);
}
}
GetWordContainer.js
class GetWordContainer extends Component {
//this state only updates once
state = {
word: this.props.word,
info: this.props.info,
partOfSpeech: this.props.parOfSpeech,
versions: this.props.versions,
shortdef: this.props.shortdef,
pronunciation: this.props.pronunciation,
}
render (){
return (
<div>
<Search
handleUpdate={this.props.handleUpdate}
setRedirect={this.props.setRedirect}
/>
<div>
{this.state.word}
</div>
<div>
{this.state.partOfSpeech}
</div>
<div>
{this.state.versions.map((v, i) => <div key={i}>{v}</div>)}
</div>
<div>
{this.state.pronunciation}
</div>
<div>
{this.state.shortdef}
</div>
</div>
);
}
}
您面临的问题是 GetWordContainer
组件中的 state
值是在初始渲染时实例化的。有例外,但总的来说,React 会尽可能地在渲染中重用相同的组件。这意味着该组件不会重新实例化,因此 state
值不会在重新呈现时发生变化。
这个问题的一个解决方案是使用适当的生命周期方法来处理组件何时重新渲染并适当地更新状态:getDerivedStateFromProps
但是,由于您似乎想直接渲染道具,我建议在 GetWordContainer
.
例如:
class GetWordContainer extends Component {
render() {
return (
<div>
<Search
handleUpdate={this.props.handleUpdate}
setRedirect={this.props.setRedirect}
/>
<div>{this.props.word}</div>
<div>{this.props.partOfSpeech}</div>
<div>
{this.props.versions.map((v, i) => (
<div key={i}>{v}</div>
))}
</div>
<div>{this.props.pronunciation}</div>
<div>{this.props.shortdef}</div>
</div>
);
}
}
您的构造函数生命周期方法仅运行一次 - 在组件初始化期间。如果您期望来自 parent 组件的新数据,您可以使用 componentDidUpdate()
或 getDerivedStateFromProps
.
componentDidUpdate(prevProps) {
if (prevProps.word || this.props.word) {
this.setState({
word
})
}
}
我注意到您的 child 组件没有操纵道具,它只是一个 display-only 容器。为什么不直接传递道具直接展示而不是走最长的路呢?您的 child 组件可以是功能组件:
const GetWordContainer = (props) => {
return (
<div>
<Search
handleUpdate={props.handleUpdate}
setRedirect={props.setRedirect}
/>
<div>
{props.word}
</div>
<div>
{props.partOfSpeech}
</div>
<div>
{props.versions.map((v, i) => <div key={i}>{v}</div>)}
</div>
<div>
{props.pronunciation}
</div>
<div>
{props.shortdef}
</div>
</div>
);
}