Reactjs 更新Redux状态后如何触发动作创建者

Reactjs 更新Redux状态后如何触发动作创建者,reactjs,redux,redux-thunk,Reactjs,Redux,Redux Thunk,我正在构建一个React组件,其中列出了用户当天发布的所有帖子。我有两个动作创造者和还原者: fetchUserList()是一个操作创建者,它获取所有用户的列表,并被还原程序状态this.props.userList fetchPosts(userId)是一个动作创建者,它接受userId作为参数,并获取今天发布的帖子。这被reducer stateThis.props.postsList 组件的外观如下所示: class PostList extends Component { comp

我正在构建一个React组件,其中列出了用户当天发布的所有帖子。我有两个动作创造者和还原者:

  • fetchUserList()
    是一个操作创建者,它获取所有用户的列表,并被还原程序状态
    this.props.userList
  • fetchPosts(userId)
    是一个动作创建者,它接受
    userId
    作为参数,并获取今天发布的帖子。这被reducer state
    This.props.postsList
  • 组件的外观如下所示:

    class PostList extends Component {
      componentDidMount() {
        this.props.fetchUserList();
      }
    
      renderPosts = () => {
        this.props.userList.forEach(user => {
          this.props.fetchUsers(user._id);
        });
        this.setState({
          renderedPosts: true
        });
      };
    
      render() {
        return (
          <div>
            {this.props.userList.length > 0 && !this.state.renderedPosts ? this.renderPosts() : ""}
          </div>
        );
      }
    
    类PostList扩展组件{
    componentDidMount(){
    this.props.fetchUserList();
    }
    renderPosts=()=>{
    this.props.userList.forEach(用户=>{
    this.props.fetchUsers(user.\u id);
    });
    这是我的国家({
    RenderPosts:true
    });
    };
    render(){
    返回(
    {this.props.userList.length>0&&!this.state.renderPosts?this.renderPosts():“”
    );
    }
    
    当React尝试渲染此组件时,它会抱怨:

    警告:在现有状态转换期间(例如在
    render
    或其他组件的构造函数中)无法更新。渲染方法应该是道具和状态的纯函数;构造函数的副作用是反模式,但可以移动到
    componentWillMount

    我尝试使用其他React生命周期方法,例如
    ComponentWillUpdate()
    ,并从那里调用操作,而不是
    render()
    方法,但没有成功


    处理这种模式的最佳方法是什么?

    首先,让我们试着理解为什么
    React
    会抱怨。您的代码试图做的是在组件渲染时更新状态。但是更新状态会导致重新渲染。因此,您可能会陷入无休止的循环:

    渲染->更新状态->渲染->更新状态->…

    出于这个原因,在渲染期间不应调用
    setState
    。让我们试着看看如何实现这一点。我们希望首先获取用户,然后为每个用户获取该用户今天发布的帖子。由于您使用
    async
    操作和
    redux thunk
    ,理论上可以将这些电话就像任何承诺一样。你可以在文档中找到几个例子。让我们来享受一些乐趣:

    // In your action creators
    function fetchUserList() {
      return function(dispatch) {
        return fetch('http://my-api/user-list').then(
          userList => {
            dispatch({
              type: 'FETCH_USER_LIST',
              userList: userList,
            });
            return Promise.resolve(userList);
          }
        );
      };
    }
    
    function fetchPosts(userId) {
      return function(dispatch) {
        return fetch(`http://my-api/users/${userId}/posts`).then(
          posts => {
            dispatch({
              type: 'FETCH_USER_POSTS',
              userId: userId,
              posts: posts,
            });
            return Promise.resolve(posts);
          }
        );
      };
    }
    
    // Now in your component
    class PostList extends Component {
      componentDidMount() {
        const { fetchUserList, fetchPosts } = this.props;
    
        fetchUserList()
          .then(users => {
            const postsRequests = users.map(user => fetchPosts(user.id));
    
            return Promise.all(postsRequests);
          })
          .then(() => this.setState({ renderedPosts: true }));
      }
    
      renderPost(post) {
        // You can add more complete render logic here
        return <p>{post}</p>;
      }
    
      render() {
        const { postsList, userList } = this.props;
        const { renderedPosts } = this.state;
    
        return (
          <div>
            {userList.length > 0 && !renderedPosts
               ? postsList.map(post => renderPost(post))
               : ""
            }
          </div>
        );
      }
    
    //在动作创建者中
    函数fetchUserList(){
    返回功能(调度){
    返回获取('http://my-api/user-list)。然后呢(
    用户列表=>{
    派遣({
    键入:“获取用户列表”,
    userList:userList,
    });
    返回Promise.resolve(用户列表);
    }
    );
    };
    }
    函数fetchPosts(userId){
    返回功能(调度){
    回传(`http://my-api/users/${userId}/posts`)。然后(
    职位=>{
    派遣({
    键入:“获取用户帖子”,
    userId:userId,
    职位:职位,
    });
    返回承诺。解决(帖子);
    }
    );
    };
    }
    //现在在您的组件中
    类PostList扩展组件{
    componentDidMount(){
    const{fetchUserList,fetchPosts}=this.props;
    fetchUserList()
    。然后(用户=>{
    const postsRequests=users.map(user=>fetchPosts(user.id));
    返回承诺。全部(后请求);
    })
    .then(()=>this.setState({rendereposts:true}));
    }
    renderPost(邮政){
    //您可以在此处添加更完整的渲染逻辑
    返回{post}

    ; } render(){ const{postsList,userList}=this.props; const{renderedPosts}=this.state; 返回( {userList.length>0&&!renderPosts ?postsList.map(post=>renderPost(post)) : "" } ); }
    有几种方法可以实现这一点,查看文档应该很有启发性!它展示了几种组合和组合较小功能以构建您自己的流程的方法。与其从
    组件didmount
    中链接这一点,我们可以有一个专门的action creator来为我们实现这一点。我希望这能给您带来更好的体验了解这些库和中间件的强大功能。我的代码片段只是一个简单的示例,它对您的代码/操作进行了一些假设,并跳过了所有“挂起”和“错误”状态


    我建议不要使用
    componentWillMount
    ,因为有充分的理由(请参阅和)。

    this.props.fetchUserList.forEach
    这是否有效?不应该是
    this.props.userList.forEach
    ?您是否尝试移动到
    componentWillMount()
    ?@Prajwal抱歉,在复制粘贴代码时出错。为什么不摆脱renderedPost状态,只使用纯组件渲染帖子?这样,只有在更改后才会重新渲染。还可以尝试fetchTodaysPostForUsers(用户ID\u列表)操作,因此只有在所有结果都可用时,状态才会更新。我假设这里的获取是异步的。感谢这个答案,我需要花费一些时间来进一步研究它。我目前正在使用async/await语法-我假设我仍然可以使用它来连接调用,如您的示例中所示。确保没有问题,花费一些时间是值得的由于您将大量使用这些模式,因此需要花时间完全掌握它们。将其转换为async/await语法应该非常容易。让我知道这是怎么回事;)我正在努力用async/await语法复制它-您有一些代码可以与我共享吗?