Как получить доступ к «селекторам» из фрагмента в наборе инструментов Redux

Итак, я все еще новичок в наборе инструментов Redux и, вероятно, что-то делаю неправильно. В любом случае мне интересно, как извлечь мои «селекторы» из моего магазина/фрагмента в Redux.

Допустим, у меня есть следующий фрагмент:

const mySlice = creatSlice({
    name: 'my-slice',
    initialState: {
      stuff: {
        primary: 'Things',
        secondary: 'Other Things',
      },
    },
    reducers: (create) => ({
      getStuff: create.asyncThunk(
        () => getSomeDataAsynchronously(),
        { ...justAssumeTheseUpdateStateWithData },
      ),
    }), 
    // this is the part I'm most interested in understanding better
    // I'm not even sure I'm doing it right. Is this how to handle
    // using arguments, or do I need to curry or something?
    selectors: {
      selectStuff: (state) => state.stuff,
      selectSpecificStuff: (state, key) => state[key] ?? 'not found',
    }
});

const store = configureStore({
  reducer: mySlice.reducer
});

Итак, вот что меня больше всего смущает. Предположим, я внедрил это хранилище в свой Provider и нахожусь в дочернем компоненте реакции:

import { useSelector } from 'react-redux';

const MyComponent = () => {
  const selectSpecificStuff = useSelector(/* how to access from my slice? */);

  return <>{selectSpecificStuff('primary')}</>;
}

Возможно ли это вообще? Кажется, я ничего не могу найти об этом в документации, что заставляет меня задаться вопросом, в чем смысл свойства selectors, если вы не можете получить к нему доступ.

Любая помощь приветствуется.


1
200
2

Ответы:

Я не пробовал селекторы внутри createSlice(). Однако без этих записей должно работать следующее:

const sliceOfInterest = useSelector(state => state['my-slice']);

и теперь вы можете получить доступ

sliceOfInterest.stuff.primary, etc.

Очевидно, вам нужно проверить, не является ли значение нулевым.

Кроме того, экспортируйте свои действия, чтобы их можно было вызывать из другого места.

// Action creators are generated for each case reducer function
export const { getStuff } = mySlice.actions;

Однако вам не нужны функции редуктора «get». Используйте функции редуктора для редактирования/изменения вашего глобального состояния. Получите к ним доступ, используя useSelector, показанный выше.

Если у вас есть другие функции-редюсеры (в той области кода, где находится getSuff), вы вызовете их следующим образом:

dispatch(getStuff(params))

Решено

Определение и доступ к селекторам

Мне любопытно, как извлечь мои «селекторы» из моего магазина/фрагмента в редукс.

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

Пример:

export const {
  selectStuff,
  selectSpecificStuff
} = myslice.selectors;

Селектор selectSpecificStuff все еще работает с состоянием среза, поэтому сначала ему потребуется доступ к state.stuff.

selectors: {
  selectStuff: (state) => state.stuff,
  selectSpecificStuff: (state, key) => state.stuff[key] ?? "not found"
}

или

selectors: {
  selectStuff: (state) => state.stuff,
  selectSpecificStuff: (state, key) => {
    const stuff = mySlice.getSelectors().selectStuff(state);
    return stuff[key] ?? "not found";
  }
}

Использование селекторов

Итак, вот что меня больше всего смущает. Предположим, я ввел это store в моем Provider, и я нахожусь на дочернем компоненте реакции:

import { useSelector } from 'react-redux';

const MyComponent = () => {
  const selectSpecificStuff = useSelector(/* how to access from my slice? */);

  return <>{selectSpecificStuff('primary')}</>;
}

Возможно ли это вообще? Кажется, я ничего не могу найти об этом в docs, что заставляет меня задуматься, в чем смысл свойства selectors? есть, если вы не можете получить к нему доступ.

Часть, которая изначально сбила меня с толку в этих селекторах, заключается в том, что они генерируются с ожиданием монтирования/внедрения в хранилище с использованием определенного значения редуктора, которое по умолчанию соответствует свойству name среза.

Пример:

import { createSlice } from '@reduxjs/toolkit';

const mySlice = createSlice({
  name: 'my-slice', // <-- default reducer path
  initialState: {
    stuff: {
      primary: 'Things',
      secondary: 'Other Things',
    },
  },
  reducers: (create) => ({
    ....
  }), 
  selectors: {
    selectStuff: (state) => state.stuff,
    selectSpecificStuff: (state, key) => state.stuff[key] ?? "not found"
  }
});

export const {
  selectStuff,
  selectSpecificStuff
} = myslice.selectors;

...
const store = configureStore({
  reducer: {
    "my-slice": mySlice.reducer // <-- mount under correct path
  }
});

Импортируйте селекторы и в обратном вызове хука useSelector передайте корневое состояние и аргумент key селектору среза.

import { useSelector } from 'react-redux';
import { selectStuff, selectSpecificStuff } from '../path/to/mySlice';

const MyComponent = () => {
  const stuff = useSelector(selectStuff);
  const primaryStuff = useSelector((state) =>
    selectSpecificStuff(state, "primary")
  );
  const secondaryStuff = useSelector((state) =>
    selectSpecificStuff(state, "secondary")
  );
  const tertiaryStuff = useSelector((state) =>
    selectSpecificStuff(state, "tertiary")
  );

  console.info({
    stuff:          // { stuff: { primary: "Things", secondary: "Other Things" } }
    primaryStuff,   // "Things"
    secondaryStuff, // "Other Things"
    tertiaryStuff,  // "not found"
  });

  ...
}

Альтернативное использование селектора

getSelectors

Использование mySlice.getSelectors() — это другой способ доступа к селекторам.

const store = configureStore({
  reducer: mySlice.reducer
});
import { useSelector } from 'react-redux';
import mySlice from '../path/to/mySlice';

const MyComponent = () => {
  const stuff = useSelector(mySlice.getSelectors().selectStuff);
  const primaryStuff = useSelector((state) =>
    mySlice.getSelectors().selectSpecificStuff(state, "primary")
  );
  const secondaryStuff = useSelector((state) =>
    mySlice.getSelectors().selectSpecificStuff(state, "secondary")
  );
  const tertiaryStuff = useSelector((state) =>
    mySlice.getSelectors().selectSpecificStuff(state, "tertiary")
  );

  console.info({
    stuff:          // { stuff: { primary: "Things", secondary: "Other Things" } }
    primaryStuff,   // "Things"
    secondaryStuff, // "Other Things"
    tertiaryStuff,  // "not found"
  });

  ...
}