【问题标题】:Redux: mapStateToProps is rendering twiceRedux:mapStateToProps 渲染两次
【发布时间】:2023-04-04 05:41:01
【问题描述】:

我最近开始学习 Redux,有些事情困扰着我。

import React, { useEffect } from "react";
import { connect, useDispatch } from "react-redux";
import Modal from "../Modal/Modal";
import history from "../../utils/history";
import { fetchPost } from "../../actions";

const PostDelete = ({ match, post }) => {
  const postId = match.params?.id;
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(fetchPost(postId));
  }, [dispatch]);
  return (
    <Modal
    />
  );
};

const mapStateToProps = (state, { match }) => {
  console.log("MSTP", state.posts[match.params?.id]) // <== CONSOLED TWICE !!
  return { post: state.posts[match.params?.id] };
};

export default connect(mapStateToProps, {})(PostDelete);

根据我的理解,当我使用 react-router 导航到这里时:

  1. 应首先调用 MSTP(从商店获取帖子)
  2. 然后 useEffect() 获取帖子(以防万一用户直接打开此页面)
  3. 它调度改变状态的动作
  4. 这会再次重新呈现 MSTP

有没有办法解决这个问题?这是一种不好的方法还是我在这里遗漏了什么?

【问题讨论】:

    标签: javascript node.js reactjs redux


    【解决方案1】:

    说明

    首先我想说你对正在发生的事情的理解是正确的。从official react-redux documentation 中,它描述了mapStateToProps 被调用每次商店更新。

    如果您有一个相当简单的mapStateToProps 对象要计算,这没问题,但如果您正在做一些更密集的事情,可能会导致性能下降。对于密集的情况,我建议使用记忆选择器,如果没有对存储进行相关更改,它将只返回先前计算的 mapStateToProps 值,而不进行任何新的计算。一个很好的库是reselect

    即使使用记忆选择器,您的console.log('MSTP') 语句也会被打印,但底层计算会更快。

    代码示例

    考虑以下示例。

    1. 组件第一次渲染
    2. useEffect 获取帖子并更新 state.posts 的商店(与此组件相关)
    3. 其他一些组件在与该组件无关的部分更新 redux 状态,例如state.comments

    这是代码和控制台输出之前使用记忆选择器

    const intensivePostsFormatting = (state) => {
       console.log('Formatting Posts');
       // do some stuff with state.posts
       return formattedPosts;
    }
    
    const mapStateToProps = ({ match, state }) => {
      console.log('MSTP');
      return {
        posts: intensivePostsFormatting(state)
       }
    }
    
    // Console Output:
    // MSTP
    // Formatting Posts
    // MSTP
    // Formatting Posts
    // MSTP
    // Formatting Posts
    

    这是代码和输出AFTER使用记忆选择器

    import { createSelector } from 'reselect';
    
    const intensivePostsFormatting = (posts) => {
       console.log('Formatting Posts');
       // do some stuff with posts
       return formattedPosts;
    }
    
    const postsSelector = createSelector(
       state => state.posts,
       posts => intensivePostsFormatting(posts)
    )
    
    const mapStateToProps = ({match, state }) => {
      console.log('MSTP');
      return {
        posts: postsSelector(state)
       }
    }
    
    // Console Output:
    // MSTP
    // Formatting Posts
    // MSTP
    // Formatting Posts
    // MSTP
    

    请注意,之前和之后的区别在于“格式化帖子”在“之前”示例中记录了 3 次,在“之后”示例中记录了 2 次。这是因为使用记忆选择器允​​许我们在更改state.posts 以外的内容时跳过计算格式化的帖子。

    【讨论】:

    • 这说得很清楚了。非常感谢您花时间解释所有这些!
    • 没问题,乐于助人:)
    猜你喜欢
    • 2016-07-03
    • 1970-01-01
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-26
    相关资源
    最近更新 更多