#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, чтобы все данные были согласованы.