【问题标题】:Different instances of a redux toolkit storeredux 工具包商店的不同实例
【发布时间】:2021-12-05 14:48:54
【问题描述】:

我正在构建一个自定义下拉组件,并且我正在使用 redux 工具包来管理状态。它工作得很好

但是当我在另一个地方重用下拉组件时,在同一页面中,“状态冲突”,所以当我打开一个下拉菜单时,另一个打开。 (这是我的下拉减速器)

import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";

interface Dropdown {
  isOpen: boolean;
  selectedValue: string;
}

export const toggleOpen = createAction("dropdown/toggleOpen");
export const changeSelectedValue = createAction<string>(
  "dropdown/changeSelectedValue"
);

const initialState = {
  isOpen: false,
  selectedValue: "-- Selecione --",
} as Dropdown;

const dropdownReducer = createReducer(initialState, (builder) => {
  builder
    .addCase(toggleOpen, (state) => {
      state.isOpen = !state.isOpen;
    })
    .addCase(changeSelectedValue, (state, action) => {
      state.selectedValue = action.payload;
    });
});

const dropdownStore = configureStore({
  reducer: dropdownReducer,
});

type RootState = ReturnType<typeof dropdownStore.getState>;
type AppDispatch = typeof dropdownStore.dispatch;

export const useDropdownDispatch = () => useDispatch<AppDispatch>();
export const useDropdownSelector: TypedUseSelectorHook<RootState> = useSelector;
export default dropdownStore;

有什么方法可以为同一家商店创建不同的“实例”,所以每个下拉菜单都有自己的? PS:我是在Dropdown组件中填充Provider,所以每个下拉菜单都有一个provider,如下:

import React from "react";
import { Provider } from "react-redux";
import ArrowDown from "../assets/icons/arrow-down";
import ArrowUp from "../assets/icons/arrow-up";
import store, {
 useDropdownSelector,
 useDropdownDispatch,
 toggleOpen,
 changeSelectedValue,
} from "../store/reducers/dropdown";
import styles from "./SingleDropdown.module.scss";

interface ItemProps {
 value: string;
 onClick?: (value: string) => void;
}

const ArrowIcon = () => {
 const isOpen = useDropdownSelector((state) => state.isOpen);
 return isOpen ? <ArrowUp /> : <ArrowDown />;
};

export const SelectItem: React.FC<ItemProps> = ({
 children,
 value,
 onClick,
}) => {
 const dispatch = useDropdownDispatch();

 const changeSelectedValueClickHandler = () => {
   dispatch(changeSelectedValue(value));
   if (onClick) onClick(value);
 };

 return (
   <div
     className={styles.dropdown__menu__items}
     onClick={changeSelectedValueClickHandler}
     id={value}
   >
     {children}
   </div>
 );
};

const SelectMenu: React.FC = ({ children }) => {
 const isOpen = useDropdownSelector((state) => state.isOpen);
 return isOpen ? (
   <div className={styles.dropdown__menu}>{children}</div>
 ) : null;
};

const InitialSelectItem = () => {
 const selectedValue = useDropdownSelector((state) => state.selectedValue);
 const dispatch = useDropdownDispatch();

 return (
   <div
     onClick={() => dispatch(toggleOpen())}
     className={styles.dropdown__field}
   >
     {selectedValue}
     <ArrowIcon />
   </div>
 );
};

export const SingleSelect: React.FC = ({ children }) => {
 return (
   <Provider store={store}>
     <div className={styles.dropdown}>
       <InitialSelectItem />
       <SelectMenu>{children}</SelectMenu>
     </div>
   </Provider>
 );
};

【问题讨论】:

  • 您应该在另一个唯一属性下维护每个输入状态。可能它应该是输入字段的名称。您可以通过使用页面/表单名称嵌套来避免跨页面的相同问题。

标签: reactjs redux react-redux redux-toolkit state-management


【解决方案1】:

一般来说,我们建议不要在 Redux 中保持这样的状态,这正是您刚刚看到的原因。它不是“全局”状态——只有一个特定的组件关心它:

https://redux.js.org/tutorials/essentials/part-2-app-structure#component-state-and-forms

现在您可能想知道,“我是否总是必须将所有应用程序的状态放入 Redux 商店?”

答案是否定的。 应用所需的全局状态应该放在 Redux 商店中。只在一个地方需要的状态应该保持在组件状态中。

如果你真的需要在 Redux 中拥有这些数据,控制一个组件的多个“实例”,它们有自己独立的状态位,你可以使用某种 normalized state structure 并跟踪每个组件的数据基于其 ID。

【讨论】:

  • 在这种情况下最好的做法是什么?将此状态更改为上下文 API,以便更好地控制组件范围的状态?我不能使用 useState,因为我需要传递 onClick 事件来设置下拉菜单对孩子不可见
猜你喜欢
  • 2021-12-09
  • 2013-04-26
  • 2021-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
  • 2016-09-30
  • 2020-02-06
相关资源
最近更新 更多