可以说我的用例是打印帖子列表。我有以下反应成分。

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.postsundefined[],因此this.state.loadedfalse,我们将进行API调用以提取。一次,获取数据,然后我应该更新为

componentWillReceiveProps(nextProps) {
    this.setState({
        loaded: nextProps.posts && nextProps.posts.length
    });
}


这将设置本地状态,最初将显示spinner/loader,然后显示postsno posts。但是,据我所知,React文档不鼓励setStatecomponentWillReceiveProps中使用,因为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);

10-02 02:08
查看更多