Я пытаюсь обновить состояние React Redux, используя обычную практику. Вы постоянно копируете свое текущее состояние в функцию возврата, а затем перезаписываете свойства, которые должны иметь новое значение.
Мой ожидаемый результат -
state.copy
обновить до
[
{ webCopy: "", id: 0 },
{ webCopy: "", id: 1 }
]
К сожалению, это пустой массив, несмотря на то, что он возвращает значение копии в виде нового массива с объектом JS.
Я пытался просмотреть результаты поиска StackOverflow для "react redux state not updating correctly"
но ни один из результатов поиска не соответствует моей ситуации.
В моем приложении я даже проверил: только
case actionTypes.ADD_COMPONENT
(первый в редукторе) активируется в этой части приложения. Это буквально нажатие кнопки, которое вызывает
ADD_COMPONENT
самостоятельно. Нет никакой активности от любого другого редуктора, который мог бы перезаписывать мое состояние пустым массивом []
.
Почему я получаю пустой массив в конце case actionTypes.ADD_COMPONENT
?
Мой оператор console.log()
даже показывает JavaScript Объект, являющийся значением для newCopy
ПРАВО, ДО ТОГО, КАК Я ВОЗВРАЩАЮ новое состояние.
Итак, вот редуктор. js. Я загрузил ПОЛНЫЙ редуктор вместо case actionTypes.ADD_COMPONENT
, где происходит ошибка:
import * as actionTypes from "./constants";
let component = "";
let idIteration = null;
let stateArray = [];
let tempCopy = [];
const initialState = {
components: [],
uniqueIdCounter: 0,
currentPage: 1,
copy: [],
siteURL: "/salespage/"
};
const reducer = (state = initialState, action) => {
switch (action.type) {
// you can probably ignore everything outside of this switch statement
// this is the important switch statement
case actionTypes.ADD_COMPONENT:
stateArray = [...state.components];
console.log("state:", state);
console.log("State Copy:", state.copy);
component = action.payload[0]; // will be "Header", "Headline", "Text Area", "Image", "Email Field", "Footer"
if (component === "Header") {
// append "Header" component to the beginning of the list
stateArray.unshift({
type: component,
id: state.uniqueIdCounter
});
} else {
// push component to the end of the list
stateArray.push({
type: component,
id: state.uniqueIdCounter
});
}
idIteration = state.uniqueIdCounter + 1;
// SEND HELP. How could state.copy possibly be anything other than a JS object after these lines?
let newCopy = [...state.copy];
newCopy.push({ webCopy: "", id: action.payload[1] });
console.log("TTTTTTTTT", newCopy);
return {
...state,
components: stateArray,
uniqueIdCounter: idIteration,
copy: newCopy // why doesn't this update the array to contain newCopy? it should.
};
// i don't know how any of this could possibly cause my state.copy to be equal to []
case actionTypes.SET_NEW:
console.log("Activating SET_NEW");
// uploads the newly reordered set of components to state
let uploadNewOrder = [...action.payload];
return {
...state,
components: uploadNewOrder
};
case actionTypes.DEL:
console.log("activating DEL");
// uploads the state less the deleted item
let uploadShortened = [...action.payload];
return {
...state,
components: uploadShortened
};
case actionTypes.PAGE_CHANGE:
console.log("activating PAGE_CHANGE");
stateArray = [...state.components];
return {
...state,
// action.payload is set in each page's ComponentDidMount()
currentPage: action.payload
};
case actionTypes.NEW_VAR:
console.log("activating NEW_VAR");
// case "NEW_VAR" fires from Customize's renderStateComponents()
stateArray = [...state.components];
tempCopy = Object.assign([], state.copy); // avoids the TypeError bug with [...state.copy]
// push an empty copy datapoint to state with a unique id to use in identifying which copy goes where in interface
let newInputFieldNumber = { webCopy: "", id: action.payload };
tempCopy.push(newInputFieldNumber);
return {
...state,
components: stateArray,
copy: tempCopy
};
case actionTypes.ADD_COPY:
console.log("activating ADD_COPY");
tempCopy = [...state.copy]; // immutably copy state.copy
let textToAdd = action.payload[0];
let indexToFind = action.payload[1];
for (let i = 0; i < tempCopy.length; i++) {
if (tempCopy[i].id === indexToFind) {
// Modify the JS object linked to the appropriate input field
tempCopy[i] = { webCopy: textToAdd, id: indexToFind };
}
}
return {
...state,
components: stateArray,
copy: tempCopy
};
case actionTypes.SET_URL:
console.log("activating SET_URL");
stateArray = [...state.components];
// TODO: handle cases like user entered www.etc.com and https://www.test.com
let domain = action.payload;
const notAllowed = [
"https://www.",
"www.",
".",
"www",
"com",
"net",
"org",
".com",
".net",
".org"
];
for (let i = 0; i < notAllowed.length; i++) {
if (domain.includes(notAllowed[i])) {
domain = domain.replace(notAllowed[i], "");
}
}
return {
...state,
components: stateArray,
siteURL: "/salespage/" + domain
};
default:
return state;
}
};
export default reducer;
Есть предложения, что попробовать? Я попытался добавить этот случай к своему редуктору и активировать его в строке после .ADD_COMPONENT
, и он все еще дает пустой массив:
case actionTypes.PREP_COPY:
let prepCopy = [...state.copy];
prepCopy.push({ webCopy: "", id: action.payload });
return {
...state,
copy: prepCopy
};
Я дал переменной-нарушителю newCopy
уникальное имя для не использовать глобальную область видимости. В случае, если это как-то важно.
Какой еще код я могу показать? Только редуктор может влиять на состояние Redux, и нет никакого другого кода, кроме .ADD_COMPONENT и (сейчас) .PREP_COPY
EDIT: Согласно советам, я пытался использовать оператор распространения с переменными при возврате состояния. Код теперь работает, если я использую оператор Spread только в ОБА действиях редуктора. Использование его только в одном из них все еще дает пустой массив. Вот так:
const reducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.ADD_COMPONENT:
// edited out some code...
let newCopy = [...state.copy];
newCopy.push({ webCopy: "", id: action.payload[1] });
console.log("newCopy", newCopy);
return {
...state,
components: stateArray,
uniqueIdCounter: idIteration,
copy: [...newCopy]
};
case actionTypes.PREP_COPY:
console.log("State.copy:", state.copy);
let prepCopy = [...state.copy];
prepCopy.push({ webCopy: "", id: action.payload });
console.log("PREPCOPY:", prepCopy);
return {
...state,
copy: [...prepCopy]
};
Так что либо я использую оба эти Действия одновременно, либо нада. Буквально: когда я использую оба, я получаю два JS объекта, добавленных за цикл. Когда я использую только один, я получаю 0 JS объектов, добавленных за цикл. Wut.
Например, я должен сообщить об ошибке команде React?
2-е редактирование: это полностью рабочая песочница кода. Проверьте операторы console.log при нажатии кнопки https://codesandbox.io/s/lucid-heisenberg-iczww