可以说我的用例是打印帖子列表。我有以下反应成分。
class App extends Component {
constructor(props) {
super(props);
this.state = {
loaded: !!(props.posts && props.posts.length)
};
}
componentDidMount() {
this.state.loaded ? null : this.props.fetchPosts();
}
render() {
return (
<ul>
{this.state.loaded
? this.props.posts.length
? this.props.posts.map((post, index) => {
return <li key={index}>{post.title}</li>;
})
: 'No posts'
: 'Loading'}
</ul>
);
}
}
fetchPosts
是一种操作,该操作进行API调用以从数据库中获取帖子,然后使用数据更新redux存储。现在,我的问题是我应该何时根据道具更新本地React状态?
最初,
this.props.posts
是undefined
或[]
,因此this.state.loaded
是false
,我们将进行API调用以提取。一次,获取数据,然后我应该更新为componentWillReceiveProps(nextProps) {
this.setState({
loaded: nextProps.posts && nextProps.posts.length
});
}
这将设置本地状态,最初将显示
spinner/loader
,然后显示posts
或no posts
。但是,据我所知,React文档不鼓励setState
在componentWillReceiveProps
中使用,因为lifecycle
挂钩在React 16中将被多次调用,并且也已弃用。因此,应该在哪个生命周期挂钩中更新本地状态?
仅在Redux中维护加载机制会更好吗?
class App extends Component {
constructor(props) {
super(props);
}
compomentDidMount() {
this.props.loaded ? null : this.props.fetchPosts();
}
render() {
return (
<ul>
{this.props.loaded
? this.props.posts.length
? this.props.posts.map((post, index) => {
return <li key={index}>{post.title}</li>;
})
: 'No posts'
: 'Loading'}
</ul>
);
}
}
在这里,所有内容仅在Redux存储中维护。如果有其他更好的方法,那么我很想知道。谢谢!
最佳答案
推荐的解决方案是将其移动到mapStateToProps
。在大多数情况下,当您需要从商店中获取数据(此处为posts
)或从商店中获取数据(此处为loading
)时,mapStateToProps
是注入数据的正确位置。通常最好使组件保持沉默,以免从存储中获取数据。同样,将状态保持在从存储派生的组件中也违反了单一真理原则,因为如果您不注意,它可能会不同步:
class App extends Component {
render() {
const {loading, posts} = this.props;
if (loading) return 'Loading';
if (!posts.length) return 'No Posts';
return (
<ul>
{posts.map((post, index) => (
<li key={index}>{post.title}</li>;
))}
</ul>
);
}
}
const mapStateToProps = ({posts}) => ({
posts
loading: !posts,
});
export default connect(mapStateToProps, /* mapDispatchToProps */)(App);