React中componentDidMount改状态未触发孙组件渲染的解决方案
这个问题的核心原因你已经找到了:React组件的挂载顺序导致子组件的初始化逻辑早于父组件的异步数据获取。具体来说,组件的执行流程是:父组件constructor → 父组件render → 子组件constructor → 子组件render → 子组件componentDidMount → 父组件componentDidMount。所以当你在父组件的componentDidMount里更新state时,子组件已经用初始的空props完成了state初始化,自然拿不到后续更新的值。
下面给你几个实用的解决方案,按推荐优先级排序:
方案1:让子组件成为受控组件(最推荐)
不要在子组件的constructor里把props存到自己的state中,直接在render阶段使用父组件传递的props。这样当父组件state更新时,子组件会自动接收到新的props并重新render,孙组件也能拿到最新值。
修改后的Search组件代码:
class Search extends Component { constructor(props){ super(props); var today = new Date(); this.state = { searchSuggestion: 'Search for tweets here', anchorEl: null, page: 0, placeName: "LOCATION", placeOptions: modelInstance.getPlaceOptions(), // 移除这里的searchInput,直接使用props } } render(){ // 直接用this.props.searchInput传递给孙组件 return( <div className='search'> <Row id='searchInput'> <SearchInput handleInput={this.handleInput.bind(this)} searchInput={this.props.searchInput} searchSuggestion={this.state.searchSuggestion} page={1} /> </Row> </div> ) } }
方案2:监听props变化更新子组件state(适用于子组件需要维护独立state的场景)
如果你的Search组件必须要维护自己的searchInput state(比如需要基于这个值做本地修改),可以通过componentDidUpdate生命周期钩子监听props的变化,手动更新子组件的state。
修改后的Search组件代码:
class Search extends Component { constructor(props){ super(props); var today = new Date(); this.state = { searchSuggestion: 'Search for tweets here', anchorEl: null, page: 0, placeName: "LOCATION", placeOptions: modelInstance.getPlaceOptions(), searchInput: props.searchInput || "", // 用初始props初始化 } } componentDidUpdate(prevProps) { // 当父组件传递的searchInput变化时,更新子组件state if (prevProps.searchInput !== this.props.searchInput) { this.setState({ searchInput: this.props.searchInput }); } } render(){ return( <div className='search'> <Row id='searchInput'> <SearchInput handleInput={this.handleInput.bind(this)} searchInput={this.state.searchInput} searchSuggestion={this.state.searchSuggestion} page={1} /> </Row> </div> ) } }
额外优化:给父组件state设置默认值
为了避免父组件第一次render时传递undefined给子组件,建议在DiscoverContainer的constructor里给所有从searchObject获取的字段设置默认值:
class DiscoverContainer extends React.Component { constructor(props){ super(props); this.state = { status: 'NULL', searchInput: "", positive: "", // 根据实际类型设置默认值,比如数字类型可以设为0 negative: "", total: "", noOfNeutral: "", until: "", placeName: "", } } // ... 其他代码不变 }
这样第一次render时,子组件拿到的props都是合法的默认值,不会出现意外的undefined问题。
内容的提问来源于stack exchange,提问作者Sahand

