Redux | дочерний компонент НЕ выполняет повторную визуализацию родительского компонента

#reactjs #redux

#reactjs #redux

Вопрос:

Код длинный, но идея заключается в следующем:

У меня есть 3 компонента: базовый компонент приложения, MapComponent, ShipComponent

Компоненты приложения вызывают MapComponent с помощью контейнера, MapComponent вызывает ShipComponent lso с помощью контейнера. К хранилищу подключены контейнеры Map и Ship. Компоненты Map и Ship используют одни и те же данные из нескольких массивов и передаются в mapStateToProps

При отправке компонента с использованием useEffect() вызывается действие для генерации данных и помещения их в хранилище.

Проблема:

Дочерний компонент (поставка компонента) выполняет повторную визуализацию просто отлично, НО карта компонента (родительская) даже НЕ указывает, что родительский компонент Map ТАКЖЕ использует тот же массив shipLocation. Компонент map и Ship получает его из одного и того же хранилища redux.

Почему дочерний компонент после выполнения действия выполняет повторную визуализацию, а родительский компонент — нет? Как мне это исправить?

В качестве теста, вместо того, чтобы передавать действие через mapDispatchToProps ShipComponent, я передал его MapComponent и через props передал его ShipComponent для его выполнения. Только после этого он обновил родительский MapComponent. Но мне нужен ShipComponent, чтобы получить действие и обновить MapComponent.

РЕДАКТИРОВАТЬ Добавлен пример кода:

Итак, корневой компонент (приложение)

 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;
  

это вызывает карту контейнера, которая передает все данные о состоянии из хранилища в компонент 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;
  

MapComponent:

 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;
  

and this MapComponent calls out ShipComponent container

 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;
  

and the ShipComponent component looks like this:

 import React, { useEffect } from "react";

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

export default ShipComponent;
  

The genShips() is an action:

 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 };
}
  

The MapComponent reducer:

 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";

Все эти контейнеры, константы, компоненты и действия находятся в разных файлах

p.s. дочерний компонент ShipComponent отлично получает данные многочипового массива shipLocation, но поскольку MapComponent (родительский) не выполняет повторную визуализацию, он этого не делает.

O и редукторы 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))
  );
}
  

Комментарии:

1. Не могли бы вы предоставить редуктор для этого genShips() или минимальный воспроизводимый пример?

2. Да, конечно. я удалю весь ненужный код, чтобы оставить минимальный пример. Я обновлю его в ближайшее время

3. @dongnhan добавил все компоненты, редукторы и код действия, удалив ненужный код для этого примера. проверено — та же проблема по-прежнему возникает с этим минимальным кодом

4. вы используете другое хранилище для приложения и компонента карты, следует помочь удалить хранилище и его поставщика в MapComponent.

5. @tuan. большое спасибо! Я думаю, мне нужно было повторить <provider> для каждого компонента, который использует хранилище. Если вы хотите опубликовать ответ как «ответ» вместо комментария, чтобы я мог пометить его как «ответ», это было бы здорово, чтобы другие, допустившие ту же ошибку, получили быстрый ответ. Еще раз спасибо! 🙂

Ответ №1:

Вы используете другое хранилище для приложения и компонента карты, следует помочь удалить хранилище и его поставщика в MapComponent. Во всем приложении должно быть только 1 хранилище redux, чтобы все данные были согласованы.