RTK: useSelector() против store.getState()

Я работаю над проектом с другим разработчиком, и мы не можем понять, как должен проходить процесс аутентификации. Мы используем RTK для управления состоянием. В EntryPoint.tsx вот мой подход:

export default function EntryPoint({ layoutHandler }: EntryPointProps) {

  const { isDarkMode, themeColors } = useContext(ThemeContext);
  const { accessToken } = useSelector((state:RootState) => state.auth)

  return (
    <>
      <StatusBar
        animated
        backgroundColor = {themeColors['neutral-00']}
        barStyle = {isDarkMode ? 'light-content' : 'dark-content'}
      />

      <View
        onLayout = {layoutHandler}
        style = {[
          globalStyles.container,
          {
            backgroundColor: themeColors['neutral-00'],
            paddingBottom:
              Platform.OS === 'android' ? styleGuide.layout.spacing.md : 0,
          },
        ]}
      >
        {!accessToken ? <AuthNavigator /> : <MainNavigator />}
      </View>
    </>
  );
}

В этом подходе во время выхода из системы все, что нужно, это удалить/уничтожить accessToken, и вы будете отправлены в стек навигатора, который содержит экраны для аутентификации (OnBoarding, Login, Verify Login)

Вот подход моего коллеги

export default function EntryPoint({ layoutHandler }: EntryPointProps) {
  const { isDarkMode, themeColors } = useContext(ThemeContext);

  const authState = store.getState().auth as AuthStateType;
  const { isOnboarded } = authState;

  return (
    <>
      <StatusBar
        animated
        backgroundColor = {themeColors['neutral-00']}
        barStyle = {isDarkMode ? 'light-content' : 'dark-content'}
      />

      <View
        onLayout = {layoutHandler}
        style = {[
          globalStyles.container,
          {
            backgroundColor: themeColors['neutral-00'],
            paddingBottom:
              Platform.OS === 'android' ? styleGuide.layout.spacing.md : 0,
          },
        ]}
      >
        {!isOnboarded ? <OnboardingNavigator /> : <AuthNavigator />}
      </View>
    </>
  );
}

По сути, теперь он переупорядочил стеки навигатора таким образом, что стек OnBoardingNavigator содержит только стек Login & AuthNavigator. Обратите внимание, что AuthNavigator теперь снова содержит экран входа в систему и MainNavigator. Выход теперь работает таким образом, что после удаления accessToken мы возвращаемся к экрану входа.

Причина его подхода в том, что он не хочет использовать useSelector, поскольку подписка на магазин обходится дорого и приведет к неизвестности и непредсказуемости.

Я серьезно с этим не согласен, так как считаю, что стоимость подписки не стоит рефакторинга всех навигационных стеков, которые теперь смешивают несколько экранов в стеках, которым они не принадлежат. Простое использование useSelector заставит приложение реагировать. Однако, по его словам, за реактивность приходится платить.

Каков наилучший подход/практика в этом случае?

Reason for his approach is he doesn't want to use useSelector as subscribing to the store is costly and will lead to unknowns and unpredictability. Я не понимаю его аргументов. Предполагая, что вы используете хороший селектор (тот, который не часто меняет значение), подписка будет недорогой. И о какой неизвестности и непредсказуемости он говорит?
Nicholas Tower 02.08.2023 18:02

"подписка на магазин дорого обходится и приведет к неизвестности и непредсказуемости" - говорит кто, кроме вашего коллеги? Выбор состояния в хуке useSelector — известная и предсказуемая сущность. Спор бессмысленный. Сообщите своему коллеге, что const authState = store.getState().auth as AuthStateType; может рассматриваться как непреднамеренный побочный эффект и что им следует использовать либо хук useSelector, либо хук useEffect с обратным вызовом store.subscribe, чтобы компонент правильно подписывался на изменения состояния.

Drew Reese 02.08.2023 18:24
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Сопровождающий Redux здесь. Пожалуйста, никогда не используйте store.getState() в своем компоненте.

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

Таким образом, вы можете оптимизировать здесь, но должны сохранить вызов useSelector.

const isOnboarded = useSelector((state:RootState) => state.auth.accessToken.isOnboarded)

намного лучше.

TLDR; не разрушайте возвращаемое значение. Стоит отметить, что @phry возвращает недеструктурированную переменную, а не деструктурированную в OP accessToken. Поскольку useSelector использует строгую проверку равенства ссылок, возврат деструктурированного значения приведет к повторному рендерингу вашего компонента при любом изменении в хранилище. Однако const accessToken = useSelector((state:RootState) => state.auth.accessToken) будет перерисовываться только при изменении accessToken.

sallf 02.08.2023 18:57

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