可以说我的用例是打印帖子列表。我有以下反应成分。
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存储。现在,我的问题是
最初,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存储中维护。如果有其他更好的方法,那么我很想知道。谢谢!
答案 0 :(得分:4)
推荐的解决方案是将其移动到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);
答案 1 :(得分:3)
2是正确的。最好仅在Redux中维护状态。否则,此组件将有两个单独的状态!