Redux-toolkit — состояние обновлено, но при его использовании все еще получается начальное значение состояния

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

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

Пожалуйста, взгляните на приведенный ниже код.

сущностьSlice.js

export const entitySlice = createSlice({
    name: 'entity',
    initialState,
    reducers: {
        setEntity: (state, action) => {
            state = action.payload;
            console.info(state.entityAttributes);
        },
    },
});

export const { setEntity } = entitySlice.actions;
export default entitySlice.reducer;

Редактор.jsx

const EntityEditor = () => {
   const effectRan = useRef(false);
   const [searchParams] = useSearchParams();
   const dispatch = useDispatch();
   const entityData1 = useSelector((state) => state.entity);

   useEffect(() => {
      if (!effectRan.current) {
         effectRan.current = true;
         getEntityData();
      }
   });

   const getEntityData = () => {
      entityOperations.getEntity(searchParams.get("PK_Entity")).then(function (response) {
         dispatch(setEntity(response));
         console.info(entityData1);
      },
         function (error) {
            console.info(error);
         }
      );
   };
}

Я получаю правильный ответ от API, и значение состояния меняется, как и ожидалось, когда я проверяю его с помощью console.info(state.entityAttributes);. Однако когда я проверяю данные с помощью console.info(entityData1);, я все равно вижу начальное значение состояния, а не обновленное. Будем очень признательны за любые подсказки о том, как это исправить.

Спасибо

Вероятно, проблема аналогична этой

James 09.06.2024 14:15

@James Было бы то же самое, если бы я использовал useState, но я использую redux-toolkit для сохранения состояния здесь.

daemonium 09.06.2024 15:12

Иногда при получении значений из хранилища Redux всегда отображается начальное значение, поскольку React делает функцию статической. Чтобы всегда получать текущее значение, вы можете использовать store.getState().

LazyJ 09.06.2024 15:43

@LazyJ, можешь ли ты привести пример использования? Пример кода на основе моего примера был бы хорош.

daemonium 09.06.2024 15:48

сущностьData1 объявлена ​​как константа, в основном для того, чтобы вы пришли к выводу, что она не может измениться (пока useSelector не запустится снова при следующем рендеринге)

James 09.06.2024 16:27
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
5
80
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Как я сказал в своем комментарии, проблема связана с тем, что JavaScript фиксирует значения в хранилище Redux во время последнего рендеринга, что означает, что он не получает обновленные значения. Я также был неправ в том, что пропустил, что вы не возвращаете новое состояние или объект полезной нагрузки, что означает, что он не установлен. Вот исправление, которое я сделал, обратите внимание, что я сделал его на TypeScript, потому что это имеет больше смысла, сдержанно предвзято, и я использовал некоторые макетные данные, так как не хотел запускать для него какой-то случайный бэкэнд.

App.tsx — ваш Editor.jsx.

import { useRef, useEffect } from 'react';
import { getMockData } from './MockData';
import { useDispatch } from 'react-redux';
import { setEntity } from './Redux/EntitySlice';
import store from './Redux/store';

const App = () => {
    const effectRan = useRef(false);
    const dispatch = useDispatch();

    useEffect(() => {
        if (!effectRan.current) {
            effectRan.current = true;
            getEntityData();
        }
    });

    const getEntityData = () => {
        getMockData().then(
            function (response) {
                dispatch(setEntity(response));
                console.info(store.getState().entity);
            },
            function (error) {
                console.info(error);
            }
        );
    };

    return <div></div>;
};

export default App;

EntitySlice.ts — вашentitySlice.js.

import { PayloadAction, createSlice } from '@reduxjs/toolkit';
import { card } from '../MockData';

const initialState: card[] = [];

export const entitySlice = createSlice({
    name: 'entity',
    initialState,
    reducers: {
        setEntity: (_, action: PayloadAction<card[]>) => {
            return action.payload;
        },
    },
});

export const { setEntity } = entitySlice.actions;
export default entitySlice.reducer;

С этой настройкой у меня все сработало. Надеюсь, это поможет, в противном случае просто оставьте комментарий, а я еще раз посмотрю и отредактирую свой ответ :-)

React не «делает функции статическими» (что это вообще значит?).

Guillaume Brunerie 09.06.2024 17:14

Правда, он не «делает их статичными», он фиксирует значения во время последнего рендеринга, что может привести к устаревшим значениям, если с тех пор изменилось состояние или реквизиты. Такое поведение похоже на поведение статической функции, всегда возвращающей одно и то же значение независимо от изменений в состоянии или реквизитах. Конечно, я могу ошибаться, если вы знаете, что на самом деле это работает по-другому, не стесняйтесь мне сказать.

LazyJ 09.06.2024 17:27

Это не характерно для React или статических методов, так ведут себя все функции в Javascript. В Javascript невозможно переназначить локальную переменную из внешней функции, например, entityData1 является локальной переменной в функции EntityEditor, поэтому вызов dispatch не может изменить ее значение.

Guillaume Brunerie 09.06.2024 17:38

Да, правда, это JavaScript, а не React.

LazyJ 09.06.2024 17:50
Ответ принят как подходящий

В вашем коде есть одна проблема и одно недоразумение.

Основная проблема заключается в том, что вы переназначаете переменную state в своем редукторе. Это то, что Redux Toolkit не может обнаружить (он может обнаруживать только мутации переменной state), вместо этого вам нужно вернуть новое состояние (как описано здесь и здесь).

// state = action.payload; // Incorrect
return action.payload; // Correct

Недоразумение заключается в том, что следующий фрагмент кода будет регистрировать новые данные:

dispatch(setEntity(response));
console.info(entityData1);

Это невозможно. В Javascript вызовы функций (например, вызов dispatch) не могут переназначать локальные переменные вызывающей функции, поэтому entityData1 не может быть другим сразу после dispatch. Однако произойдет следующее: React запланирует повторную отрисовку компонента, а это означает, что ваш компонент будет вызван еще раз, на этот раз с новыми данными. Поэтому вам следует поместить console.info(entityData1) прямо в тело компонента, если вы хотите, чтобы он изменился.

Другие вопросы по теме