我正在使用redux,我不确定为什么我在try 访问时会获得初始状态,但它在redux dev工具中显示已更新的状态.

我正在做的事情: 我有两个按钮"Yes","No",在Reducer中,我有初始状态,所以当我点击"yes"按钮时,我使用调度方法更新初始状态,我可以在redux dev工具中看到更新的状态,但当我在"No"按钮的单击功能中从redux访问状态时,它显示初始状态:

reducer.js

import { SET_MODAL_DETAILS, CLEAR_MODAL_DETAILS } from "../actions/types";

const initialState = {
  modalInfo: {
    isOpen: false,
    modalName: "",
    title: "",
    content: "",          
  },
};

const modal = (state = initialState, action) => {
  const { type, payload } = action;

  switch (type) {
    case SET_MODAL_DETAILS:
      return { ...state, modalInfo: payload };

    case CLEAR_MODAL_DETAILS:
      return { ...state, modalInfo: null };

    default:
      return state;
  }
};
export default modal;

action.js

import {SET_MODAL_DETAILS, CLEAR_MODAL_DETAILS} from "./types";

export const setModalDetails = (payload) => ({
    type: SET_MODAL_DETAILS,
    payload: payload,
});

export const clearModalDetails = () => ({
    type: CLEAR_MODAL_DETAILS,
});

store.js

import { createStore, applyMiddleware } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
import checkTokenExpiration from "./checkToken";

const middleware = [thunk];

const store = createStore(
  rootReducer,
  process.env.NODE_ENV === "production"
    ? applyMiddleware(...middleware, checkTokenExpiration)
    : composeWithDevTools(applyMiddleware(...middleware, checkTokenExpiration))
);

export default store;

student.js

import { connect } from "react-redux";
import Button from "@mui/material/Button";
import { setModalDetails } from "../../redux/actions/modal";

const Student = ({ setModalDetails, modal: { modalInfo } }) => {
  const handleYesButton = () => {
    setModalDetails({
      ...modalInfo,
      isOpen: true,
      title: "Confirm Modal",
      content: "Do you want to change status?",
      modalName: "confirmModal",
    });
  };

  const handleNoButton = () => {
    console.log(modalInfo); // returns initial state while I have updated via above funtion
  };

  return (
    <>
      <Button onClick={handleYesButton}>Yes</Button>
      <Button onClick={handleNoButton}>No</Button>
    </>
  );
};

const mapStateToProps = (state) => ({
  modal: state.modal,
});

export default connect(mapStateToProps, { setModalDetails })(Student);

推荐答案

如果我从父组件传递两个函数,则它不起作用 不出所料,但如果我在子组件中同时使用这两个函数,如 student.js,那么它就起作用了.你能建议一下为什么吗?

这一切都在Student(Student.js)中运行,因为Student是从store 直接订阅state.modal状态的.当存储更新时,用注入为props 的最新 Select 的modal状态值重新呈现Student,并将modal.modalInfo重新封闭在handleNoButton函数范围内.当点击"否"按钮时,它具有当前的modalInfo值.

在按钮点击处理程序aren'tStudentA(StudentA.js)中工作的情况下,这是因为您已经关闭了某个本地州中从未更新的state.modal.modalInfo的陈旧副本.

const Parent = ({ setModalDetails, modal: { modalInfo } }) => {
  const handleYesButton = () => {
    setModalDetails({
      ...modalInfo,
      isOpen: true,
      title: "Confirm Modal",
      content: "Do you want to change status?",
      modalName: "confirmModal"
    });
  };

  const handleNoButton = () => {
    console.log("from parent: ", modalInfo);
  };

  const [
    confirmOptions,
    setConfirmOptions // <-- never called to update confirmOptions
  ] = useState({
    buttons: [
      {
        label: "Yes",
        onClick: handleYesButton // <-- store state closed over!
      },
      {
        label: "No",
        onClick: handleNoButton  // <-- store state closed over!
      }
    ]
  });

  return <StudentA options={confirmOptions} />;
};

当Redux状态被更新并重新呈现Parent次时,setConfirmOptions不会被调用来更新confirmOptions值,因此StudentA将传递当前的confirmOptions状态,该状态现在包含过时的Redux状态值.

如果您想创建一个要传递的Options对象,那么只需直接计算并传递它即可.这样,无论何时渲染Parent,都会使用当前选定状态值创建新的confirmOptions对象.

示例:

const confirmOptions = {
  buttons: [
    {
      label: "Yes",
      onClick: handleYesButton
    },
    {
      label: "No",
      onClick: handleNoButton
    }
  ]
};

return <StudentA options={confirmOptions} />;

Edit why-does-useselector-return-initial-state-while-in-redux-dev-tool-it-shows-updat

如果这样做会触发超过StudentA次的渲染,或者如果创建对象需要进行昂贵的计算,则应该使用useMemo挂钩来记忆并提供稳定的Options对象.但是,请注意,handleYesButtonhandleNoButton在创建confirmOptions对象时是外部依赖项,因此也需要对它们进行记忆以便提供稳定的引用.

示例:

const handleYesButton = useCallback(() => {
  setModalDetails({
    ...modalInfo,
    isOpen: true,
    title: "Confirm Modal",
    content: "Do you want to change status?",
    modalName: "confirmModal"
  });
}, [setModalDetails, modalInfo]);

const handleNoButton = useCallback(() => {
  console.log("from parent: ", modalInfo);
}, [modalInfo]);

const confirmOptions = useMemo(
  () => ({
    buttons: [
      {
        label: "Yes",
        onClick: handleYesButton
      },
      {
        label: "No",
        onClick: handleNoButton
      }
    ]
  }),
  [handleNoButton, handleYesButton]
);

return <StudentA options={confirmOptions} />;

或者因为在Parent中没有引用handleYesButtonhandleNoButton,所以可以将它们移到useMemo钩子回调中.

const confirmOptions = useMemo(
  () => ({
    buttons: [
      {
        label: "Yes",
        onClick: () => {
          setModalDetails({
            ...modalInfo,
            isOpen: true,
            title: "Confirm Modal",
            content: "Do you want to change status?",
            modalName: "confirmModal"
          });
        }
      },
      {
        label: "No",
        onClick: () => {
          console.log("from parent: ", modalInfo);
        }
      }
    ]
  }),
  [modalInfo, setModalDetails]
);

return <StudentA options={confirmOptions} />;

Javascript相关问答推荐

React:未调用useState变量在调试器的事件处理程序中不可用

如何为GrapesJS模板编辑器创建自定义撤销/重复按钮?

使用useup时,React-Redux无法找到Redux上下文值

如何分配类型脚本中具有不同/额外参数的函数类型

深嵌套的ng-container元素仍然可以在Angular 布局组件中正确渲染内容吗?

如何将连续的十六进制字符串拆分为以空间分隔的十六进制块,每个十六进制块包含32个二元组?

Angular 17—每当一个布尔变量变为真时触发循环轮询,只要它保持为真

还原器未正确更新状态

在使用HighChats时如何避免Datatables重新初始化错误?

我怎么在JS里连续加2个骰子的和呢?

在运行时使用Next JS App Router在服务器组件中运行自定义函数

为什么我的getAsFile()方法返回空?

WP Bootstrap NavWaker:下拉菜单一次打开所有下拉菜单

将基元传递给THEN处理程序

如何使用Astro优化大图像?

如何更改Html元素S的 colored颜色 ,然后将其褪色为原始 colored颜色

与在编剧中具有动态价值的定位器交互

是否设置以JavaScript为背景的画布元素?

更改管线时不渲染组件的react

如果未定义,如何添加全局变量