#reactjs #redux #react-redux #render
#reactjs #redux #реагировать-redux #визуализация
Вопрос:
Я пытаюсь обновить конкретное свойство свойства моего состояния, используя общую функцию, которая примет текущее состояние, имя свойства и новое значение свойства в качестве параметра и вернет состояние с обновленным значением для свойства. Но мой компонент react не выполняет повторный рендеринг с обновленным значением. Что именно я здесь делаю не так?
Используя инструменты разработчика Chrome, когда я проверил новый объект состояния, у него обновленное значение, но моя функция рендеринга компонента react больше не вызывается
ниже приведен фрагмент кода, написанный на моем reducer
языке для обновления функции:
function App(state = initialState, action) {
switch (action.type) {
case ON_CHANGE:
let newState = Utilities.updateProperty(
state,
action.change.key,
action.change.value
);
return newState;
case DIFFERENT_ACTION:
// TODO implementation
return state;
default:
return initialState;
}
}
И ниже приведен код, написанный в Utilities.updateProperty
функции:
updateProperty(object, key, value) {
let keys = key.split(".");
let obj = object;
for (var i = 0; i < keys.length - 1; i ) {
obj = obj[keys[i]];
}
obj[keys[keys.length - 1]] = value;
return object;
}
Когда я добавил точку останова в строке, где return newState;
написано, я вижу, что значение здесь полностью обновлено. Итак, я ожидал, что мой компонент повторно отобразит новое значение.
Если я изменю свой return newState
, как показано ниже, он будет работать должным образом:
return {
...newState,
...{
now: new Date()
}
};
Ответ №1:
Сначала вам нужно распространить свое состояние, чтобы оно стало новым объектом
updateProperty(object, key, value) {
let keys = key.split(".");
let obj = { ...object }; // let obj = object;
for (var i = 0; i < keys.length - 1; i ) {
obj = obj[keys[i]];
}
obj[keys[keys.length - 1]] = value;
return obj; // return object;
}
Комментарии:
1. Это сработало, как ожидалось. Спасибо. Пожалуйста, предоставьте некоторые объяснения по этому поводу, почему это должен быть новый объект, почему он не работает с существующим.
2. это будет работать для ключа с одной частью, но это предназначено для работы с пунктирными ключами. Довольно уверен, что ему нужно будет разрушать объект для каждого шага. ie
obj = {...obj[keys[i]]}
. Я бы предложил объединитьimmer
иlodash.set
, чтобы все было намного проще.3. @PiccazaDe В основном проверяет, изменилось ли состояние, сопоставляя его с помощью оператора идентификации
===
с предыдущим объектом состояния. Если вы изменяете свой объект состояния, изменяя его внутренние значения, например,state[key] = val
, сам объект состояния по-прежнему имеет тот же идентификатор (адрес в памяти), поэтому redux не знает, что состояние изменилось. Как указано lecstor, вам также потребуется распространить ваши внутренние объекты, если они не являются примитивами, поэтому ваша служебная функция не будет работать во всех случаях.4. @Eugene Хорошо, теперь я это понимаю. Итак, в этом случае, как только я обновлю этот код,
let obj = { ...object };
мне не нужно будет изменять этоobj = {...obj[keys[i]]}
правильно, поскольку obj уже является новым объектом со ссылкой на новую адресную память, поэтому, даже если я изменю значения внутреннего уровня, он также будет работать отлично. Это правильно?5. Я бы посоветовал сначала попробовать написать ваши редукторы вручную вместо создания универсального утилитарного метода, чтобы вы лучше понимали, как работают редукторы и какие части состояния необходимо распространить в какой момент. Когда вы распространяете определенный объект, объекты, которые он содержит в нем, не копируются глубоко, а просто ссылаются на вновь распространяемый объект.
Ответ №2:
Я бы выбрал что-то подобное, что охватывало бы все базы (непроверенные).
import produce from "immer";
import set from "lodash.set";
updateProperty(object, key, value) {
return produce(object, draft => set(draft, key, value))
}
Комментарии:
1. Я должен обновить базу кода с помощью
lodash
, это довольно чисто и опрятно. Также не нужно снова изобретать эти колеса. Спасибо.