【问题标题】:Redux | child component does NOT re-render parent component还原 |子组件不会重新渲染父组件
【发布时间】:2021-01-24 01:59:36
【问题描述】:

代码很长,但思路是这样的:

我有 3 个组件 Base App 组件、MapComponent、ShipComponent

App 组件使用容器调用 MapComponent,MapComponent 调用 ShipComponent 也使用容器。 Map 和 Ship 容器都连接到 store。 Map 和 Ship 组件使用相同的多数组数据并传递给mapStateToProps

在使用 useEffect() 的组件 Ship 中,调用一个动作来生成数据并将其放入存储中。

问题:

子组件(组件 Ship)重新渲染得很好,但组件 Map(父组件)甚至不使用父 Map 组件也使用相同的 shipLocation 数组。 map 和 Ship 组件都从同一个 redux store 中获取。

为什么子组件在执行动作后会重新渲染而父组件却没有?我该如何解决?

作为测试,我没有将动作通过mapDispatchToProps 传递给 ShipComponent,而是将其传递给 MapComponent 并通过 props 将其传递给 ShipComponent 以使其执行。只有这样它才更新了父 MapComponent。但我需要 ShipComponent 来获取操作并更新 MapComponent。

编辑添加代码示例:

所以根组件(App)

import React from "react";
import { Provider } from "react-redux";
import Map from "../containers/Map";
import mainStore from "../store";

const store = mainStore();

function AppComponent(props) {
  return (
    <Provider store={store}>
      <Map />
    </Provider>
  );
}

export default AppComponent;

调用容器 Map 将所有状态数据从 store 传递到组件 MapComponent

import { connect } from "react-redux";
import MapComponent from "../components/MapComponent";

const mapStateToProps = ({ shipR }) => {
  return {
    shipLocation: [...shipR.shipLocation],
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
  };
};

const Map = connect(mapStateToProps, mapDispatchToProps)(MapComponent);

export default Map;

地图组件:

import React from "react";
import { Provider } from "react-redux";
import mainStore from "../store";
import Ship from "../containers/Ship";

const store = mainStore();

function MapComponent(props) {
  return (
    <div id="__Map__">
          {
            <Provider store={store}>
              <Ship />
            </Provider>
          }
    </div>
  );
}

export default MapComponent;

这个 MapComponent 调用了 ShipComponent 容器

import { connect } from "react-redux";
import ShipComponent from "../components/ShipComponent";
import { generateDefaultShips, shipToggle } from "../actions/shipAction";

const mapStateToProps = ({ shipR }) => {
  return {
    shipLocation: [...shipR.shipLocation],
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    genShips() {
      dispatch(generateDefaultShips());
    },
  };
};

const Ship = connect(mapStateToProps, mapDispatchToProps)(ShipComponent);

export default Ship;

ShipComponent 组件如下所示:

import React, { useEffect } from "react";

function ShipComponent(props) {
  useEffect(() => {
    props.genShips();
  }, []);
  return (
    <div className="ship"></div>
  );
}

export default ShipComponent;

genShips() 是一个动作:

import { SHIP_GENERATION_RESULT } from "../constants";

export function generateDefaultShips() {
  let arr = [];
  for (let x = 0; x < 7; x++) {
    arr[x] = [];
    for (let y = 0; y < 11; y++) arr[x][y] = null;
  }
  return { type: SHIP_GENERATION_RESULT, ships: arr };
}

MapComponent 减速器:

const initiateState = {
};

function mapReducer(state = initiateState, action) {
  return state;
}

export default mapReducer;

和 ShipComponent 减速器:

import {
  SHIP_GENERATION_RESULT,
} from "../constants";

const initiateState = {
  shipLocation: [],
};

function shipReducer(state = initiateState, action) {
  switch (action.type) {
    case SHIP_GENERATION_RESULT: {
      return {
        ...state,
        shipLocation: action.ships,
      };
    }
    default:
      return state;
  }
}

export default shipReducer;

和常量 index.js 包含: export const SHIP_GENERATION_RESULT = "SHIP_GENERATION_RESULT";

所有这些容器、常量、组件和操作都在不同的文件中

附言子组件 ShipComponent 可以很好地获取 shipLocation 多数组数据,但由于 MapComponent(父级)不会重新渲染,所以他不会。

O 和 reduxers index.js:

import { combineReducers } from "redux";
import mapReducer from "./mapReducer";
import shipReducer from "./shipReducer";

const allReducers = combineReducers({
  mapR: mapReducer,
  shipR: shipReducer,
});

export default allReducers;

存储 index.js:

import { createStore, applyMiddleware } from "redux";
import thunkMiddleware from "redux-thunk";
import allReducers from "../reducers";
import { composeWithDevTools } from "redux-devtools-extension";

export default function mainStore(prevState) {
  return createStore(
    allReducers,
    prevState,
    composeWithDevTools(applyMiddleware(thunkMiddleware))
  );
}

【问题讨论】:

  • 您能否为genShips() 提供reducer 或最小的可重现示例?
  • 是的。 imma 删除所有不需要的代码,留下一个最简单的例子。我会尽快更新它
  • @dongnhan 添加了所有组件、reducer 和操作代码,同时删除了此示例不需要的代码。经过测试 - 使用此最低代码仍然会出现同样的问题
  • 您正在为 App 和 Map 组件使用不同的商店,应该帮助删除商店及其在 MapComponent 中的提供者。
  • @tuan.tran OMG 谢谢!我很难我需要为使用商店的每个组件重复 。如果您想将答案发布为“答案”而不是评论,那么我可以将其标记为“答案”,这将是非常棒的,这样其他犯过同样错误的人就会有一个快速的答案。再次感谢! :)

标签: reactjs redux


【解决方案1】:

您正在为 App 和 Map 组件使用不同的商店,应该帮助删除商店及其在 MapComponent 中的提供者。所有应用中应该只有 1 个 redux store 才能使所有数据保持一致。

【讨论】: