React类组件setState更新state后控制台打印正常但页面不渲染如何解决?
问题原因
- 核心问题是你将异步请求方法
getUnread放在了constructor构造函数中执行。构造函数执行阶段组件还未完成挂载,此时如果异步请求返回速度过快,在组件首次挂载完成前就执行setState,React会仅修改state的内存值但不会触发重渲染,因此会出现控制台能打印新值、页面却显示初始值的情况。 - 你能在
setState之后直接打印到新值,是因为异步请求回调不属于React管控的执行上下文,此时的setState会同步更新state的内存值,不会走批量更新逻辑。 - 切页返回后组件会重新挂载,此时内存中已经更新的state会作为初始值渲染,所以显示正常。
解决方法
- 将
getUnread的调用从构造函数移到componentDidMount生命周期函数中,componentDidMount会在组件完成挂载后触发,此时执行setState一定会触发重渲染,修改后的代码如下:
class Home extends Component { constructor(props) { super(props); this.state = { unread: 0, } } componentDidMount() { // 组件挂载完成后再发起异步请求 this.getUnread() } getUnread = async () => { let data = await Chatapi.get(`count/${this.props.auth.user.id}/`).then(({ data }) => data); this.setState({ unread: data.count }, () => { // setState第二个参数为更新完成后的回调,可在这里确认更新结果 console.log(this.state.unread) }); } render() { const { auth } = this.props; return ( <div> {this.state.unread} </div> ) } }
- 如果修改后仍存在问题,可排查两个场景:
- 确认当前组件不是继承自
PureComponent,且unread的值不存在浅比较无法识别的类型问题(比如返回值是对象/数组且修改了原引用) - 排查是否有其他生命周期函数或方法在
setState之后又将unread重置为0
内容的提问来源于stack exchange,提问作者Ruma
相关产品推荐
相关产品推荐

