React+Firebase+Redux编辑页状态无法更新,仅刷新生效求助
看起来你遇到的核心问题是Firestore异步数据加载和React生命周期的配合问题,再加上一些小的拼写疏漏,导致组件初始化时拿不到数据,只有刷新后才生效。我来一步步帮你解决:
1. 先修正拼写错误
首先注意到你写的mapDispatshToProps有拼写错误——正确写法是mapDispatchToProps(少了一个c),这个错误会导致你的editPost方法无法正确绑定到Redux dispatch,先把这个改过来:
const mapDispatchToProps = (dispatch, ownProps) => { return { editPost: (id, post) => dispatch(editPost(id, post, ownProps.history)) }; };
2. 优化Firestore数据监听,只加载当前需要的文档
你现在用firestoreConnect([{ collection: "posts" }])会加载整个posts集合,但编辑页面只需要当前id对应的单个文档。更高效的方式是根据路由参数的id监听指定文档,这样数据加载完成后组件会立即收到更新:
export default compose( connect( mapStateToProps, mapDispatchToProps ), firestoreConnect((ownProps) => [ { collection: "posts", doc: ownProps.match.params.id } // 只监听当前id的目标文档 ]) )(CreatePost); // 这里建议确认组件名,如果是编辑页面可以改成EditPost,避免混淆
这样配置后,Firestore会精准获取你需要的那篇文章,数据就绪后自动更新Redux store,触发组件重新渲染。
3. 替换废弃的componentWillReceiveProps
componentWillReceiveProps已经被React官方废弃,推荐使用componentDidUpdate来处理props变化后的状态更新,同时添加条件判断避免不必要的setState:
componentDidUpdate(prevProps) { // 只有当post props发生变化,且post存在时,才更新组件状态 if (prevProps.post !== this.props.post && this.props.post) { const { title, content } = this.props.post; this.setState({ title, content }); } }
4. 调整componentDidMount的逻辑
因为Firestore数据是异步加载的,componentDidMount执行时this.props.post大概率还是null,所以这里不需要直接从props设置状态,交给componentDidUpdate处理数据加载完成后的状态更新即可:
componentDidMount() { // 初始化空状态,等待数据加载完成后由componentDidUpdate更新 this.setState({ title: "", content: "" }); }
问题根源总结
- Firestore数据加载是异步的,组件挂载时Redux store里的
posts还未被填充,所以componentDidMount里的post是null - 原
firestoreConnect监听整个集合,数据量更大、加载更慢,且只有集合整体更新才会触发组件刷新,而非目标文档的变化 componentWillReceiveProps未做props变化判断,可能导致无效状态更新,且该生命周期钩子存在潜在bug风险
修改后的代码应该能解决控制台输出null、状态无法实时更新的问题,无需刷新页面就能自动获取文章数据并填充到输入框中。
内容的提问来源于stack exchange,提问作者ABS zarzis

