Different instances of a redux toolkit store

I'm building a custom dropdown component and i'm using redux toolkit to manage the state. It works just fine

example of dropdown

But when I reuse the dropdown component in another place, in the same page, the "states conflicts", so when I open one dropdown, the another opens to. (This is my dropdown reducer)

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;

Is there any way that I can create different "instances" of the same store, so each dropdown has it's own? PS: I'm populating the Provider in the Dropdown component, so there is one provider to each dropdown, as follow:

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>
 );
};

Upvotes: 1

Views: 1115

Answers (1)

markerikson
markerikson

Reputation: 67547

Generally, we would suggest not keeping state like this in Redux, for exactly the kind of reason you just saw. It isn't "global" state - only one specific component cares about it:

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

By now you might be wondering, "Do I always have to put all my app's state into the Redux store?"

The answer is NO. Global state that is needed across the app should go in the Redux store. State that's only needed in one place should be kept in component state.

If you truly need to have this data in Redux, and control multiple "instances" of a component with their own separate bits of state, you could use some kind of a normalized state structure and track the data for each component based on its ID.

Upvotes: 1

Related Questions