Как использовать инструментарий Redux с React Native

При разработке надежных веб- или мобильных приложений (apps) внутренняя обработка состояния, как это принято в компонентах React Native, не всегда идеальна. При неправильном подходе это может быстро стать очень грязным. В подобных ситуациях обычно рекомендуется использовать библиотечные инструменты, такие как Redux.

В этой статье мы рассмотрим различные шаги по управлению потоком состояний в простом приложении React Native с помощью набора инструментов Redux.

Что такое Redux & Redux Toolkit?

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

Redux Toolkit — это официальный набор инструментов Redux для разработки эффективных приложений React-Redux. Он был разработан для упрощения написания общей логики Redux и решения обычных трудностей, связанных с использованием основной библиотеки Redux.

Например:

  • Настройка хранилища Redux
  • Создание фрагментов состояния редуктора
  • Написание неизменяемого кода обновления состояния

При использовании Redux Toolkit вместо основного Redux способ реализации этих функций меняется.

Глоссарий Redux

Действие

Действие — это простой объект, который указывает на желание изменить состояние в хранилище Redux. Требуется, чтобы действия указывали полезную нагрузку и атрибут типа, который описывает, какого рода изменение должно быть сделано в состоянии. Для успешного выполнения действий требуются редукторы.

Редуктор

Редуктор — это чистая функция, которая принимает два аргумента: текущее состояние и действие, возвращающее результат нового состояния. Редукторы не изменяют исходное состояние напрямую; скорее, они создают копию состояния и изменяют ее.

Диспетчер

Диспетчерская функция» — это функция, которая принимает синхронный или асинхронный объект действия и отправляет его на выполнение редуктору.

Slice

Набор редукторов и действий, которые работают вместе для реализации одной функции приложения.

Магазин

Согласно официальной документации Redux, магазин — это объект, который хранит все дерево состояний приложения. В приложении Redux может быть только один магазин.

Использование набора инструментов Redux с React Native

Предварительные условия

  • Базовые знания о React Native.
  • Node.js LTS >= v14.x.x (рекомендуется v16.14.2).
  • Установлен менеджер пакетов, например npm или yarn.
  • Установлен Expo CLI.
  • Знание концепций Redux.

ПРИМЕЧАНИЕ: Эта статья не является учебником по React Native и не будет посвящена концепциям React Native.

Настройка проекта

Приложение, которое мы будем создавать, представляет собой простой генератор случайных цветов, и для простоты мы будем использовать Expo CLI для создания и запуска нашего приложения.

Полный исходный код приложения вы можете найти на этом репозитории Github.

В терминале вашего компьютера выполните следующие команды:

expo init redux-toolkit-guide

cd redux-toolkit-guide
Войти в полноэкранный режим Выйти из полноэкранного режима

В качестве шаблона выберите ‘- Managed Workflow-blank’.

Теперь мы установим некоторые необходимые зависимости для нашего приложения, включая @react-navigation/native, react-native-screens и react-native-safe-area-context.

Последние инструкции по установке см. в официальной документации по библиотеке React Navigation.

yarn add @react-navigation/native

expo install react-native-screens react-native-safe-area-context
Вход в полноэкранный режим Выход из полноэкранного режима

Создание интерфейса приложения

Откройте приложение redux-toolkit-guide в редакторе кода (рекомендуется VS Code) и создайте структуру файлов.

  1. Создайте папки src и store в корне проекта.
  2. Внутри store создайте файл colorSlice.js и store.js.
  3. Создайте папку screen внутри src.
  4. Внутри папки screens создайте файл HomeScreen.js и импортируйте приведенный ниже код.
import React from "react";
import { StatusBar } from "expo-status-bar";
import {
  Text,
  View,
  StyleSheet,
  TouchableOpacity,
  FlatList,
} from "react-native";

const HomeScreen = () => {
  return (
    <View>
      <StatusBar style="dark" />
      <TouchableOpacity
        onPress={() => //empty anonymous function}
        style={styles.button}
      >
        <Text style={{ fontSize: 20 }}>Generate Random Color</Text>
      </TouchableOpacity>
      <FlatList
        keyExtractor={(item) => item}
        data={color}
        style={{ marginTop: 15 }}
        renderItem={({ item }) => {
          return (
            <View
              style={{
                backgroundColor: item,
                height: 150,
                width: 150,
                alignSelf: "center",
                margin: 10,
              }}
            />
          );
        }}
      />
    </View>
  );
};

export default HomeScreen;

const styles = StyleSheet.create({
  button: {
    alignSelf: "center",
    borderWidth: 1,
    borderRadius: 10,
    padding: 10,
    marginTop: 20,
  },
});
Вход в полноэкранный режим Выход из полноэкранного режима

src/screens/HomeScreen.js

Переопределите App.js следующим фрагментом кода:

import * as React from "react";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import HomeScreen from "./src/screens/HomeScreen/HomeScreen";

const Stack = createNativeStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default () => {
  return <App />;
};
Вход в полноэкранный режим Выход из полноэкранного режима

App.js

Запускаем expo start в нашем терминале, чтобы запустить среду разработчика. Наше приложение должно выглядеть следующим образом:

Настройка хранилища Redux

Redux Toolkit сокращает длину логического кода Redux, который мы должны написать в нашем приложении. Он использует API configureStore вместо API createStore из основного Redux для создания магазина. configureStore также автоматически устанавливает расширение Redux DevTools и некоторое промежуточное ПО.

import { configureStore } from "@reduxjs/toolkit";

export const store = configureStore({
  reducer: { },
});
Вход в полноэкранный режим Выход из полноэкранного режима

store/colorSlice.js

В хранилище хранится один корневой объект reducer для всех срезов состояния в приложении.
Теперь нам нужно обернуть наш компонент приложения с store с помощью React-Redux Provider. Это гарантирует, что наш Redux store находится на самом верхнем уровне и доступен всему приложению React Native.

...

import { store } from "./store/store";
import { Provider } from "react-redux";

... 

export default () => {
  return (
    <Provider store={store}>
      <App />
    </Provider>
  );
};
Вход в полноэкранный режим Выход из полноэкранного режима

App.js

Создание фрагментов набора инструментов Redux

Далее мы создадим фрагмент состояния для обработки всех действий и функций редуктора, связанных с генерацией случайного цвета в нашем приложении. Импортируя и вызывая createSlice в коде ниже, мы определяем внутри него;

  • name для идентификации среза.
  • значение initialState. Оно определяет, каким будет состояние при первом запуске приложения (как и при использовании хука React useState).
  • функция reducer, определяющая, как будет обновляться состояние. В блоке кода мы берем результат функции randomRgb и добавляем его к исходному массиву цветов.
import { createSlice } from "@reduxjs/toolkit";

const initialState = {
//Initialstate value is an empty array to hold all the colors generated
  value: [],
};

//A function to generate random RGB values
const randomRgb = () => {
  const red = Math.floor(Math.random() * 256);
  const green = Math.floor(Math.random() * 256);
  const blue = Math.floor(Math.random() * 256);

  return `rgb(${red}, ${green}, ${blue})`;
};

//state slice
export const colorSlice = createSlice({
  name: "color",
  initialState,
  reducers: {
    setColor: (state) => {
      state.value = [...state.value, randomRgb()];
    },
  },
});

// Action creators are automatically generated for each case reducer function 
export const { setColor } = colorSlice.actions;

export default colorSlice.reducer;
Вход в полноэкранный режим Выход из полноэкранного режима

store/colorSlice.js

При написании основной логики Redux мы избегаем прямого изменения значения состояния. Но с помощью Redux Toolkit мы можем писать мутирующий код в редукторах и преобразовывать его в неизменяемые копии.

ПРИМЕЧАНИЕ: Мы можем писать мутирующий код только внутри API createSlice или createReducer.

Вы заметите, что мы не определили никаких объектов действия в нашем коде. Это потому, что Redux Toolkit позволяет нам создавать действия на лету. Здесь мы устанавливаем функции case, определенные в нашем редукторе, в colorSlice.actions. Затем автоматически создается создатель действия, используя имя редуктора в качестве типа действия.

После этого мы можем импортировать и добавить срез в корневой reducer магазина.

...
import colorSlice from "./colorSlice";

export const store = configureStore({
  reducer: {
    color: colorSlice,
  },
});
Вход в полноэкранный режим Выход из полноэкранного режима

store/store.js

useSelector и useDispatch

Мы успешно настроили систему Redux для нашего приложения. Теперь все, что нам нужно, это иметь возможность читать текущее состояние в homeScreen.js и отправлять действие нашему редуктору.

Для этого мы будем использовать хук useSelector, который даст нам доступ к состоянию нашего redux, и хук useDispatch, который позволит нам диспетчеризировать действия.

...

import { useDispatch, useSelector } from "react-redux";
import { setColor } from "../../../store/colorSlice";

...

const HomeScreen = () => {

  const color = useSelector((state) => state.color.value); //reading the state 
  const dispatch = useDispatch();

  return (
        ...

      <TouchableOpacity
        onPress={() => dispatch(setColor())}
        ...
      >
        <Text style={{ fontSize: 20 }}>Generate Random Color</Text>
      </TouchableOpacity>

        <FlatList
        data={color}
                ...
      />
  );
};

export default HomeScreen;

...
Вход в полноэкранный режим Выход из полноэкранного режима

src/screens/homescreen.js

Мы импортируем useDispatch и useSelector из React-Redux, а также созданный нами редуктор setColor. Захватив наше текущее состояние с помощью state.color.value, мы устанавливаем его в качестве элемента данных в нашем Flatlist. Затем, вызвав useDispatch в качестве диспетчера и передав setColor в нашем обратном вызове onPress, мы можем отправить действие в соответствующий случай reducer.

Готово! Теперь наше приложение React Native может генерировать случайные цвета.

Когда использовать Redux?

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

Так когда же нам следует использовать Redux?

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

Заключение

В этом уроке мы рассмотрели, что такое Redux, основные термины в Redux и Redux Toolkit. Мы также рассмотрели основные шаги по интеграции Redux Toolkit в React Native приложение через

  1. Создание хранилища с помощью configureStore
  2. Предоставление этого хранилища для нашего приложения
  3. Создание фрагментов редуктора с помощью createSlice
  4. и чтение и обновление состояния с помощью useSelector и useDispatch.

Для дальнейшего изучения я рекомендую обратиться к официальной документации Redux.

Оцените статью
devanswers.ru
Добавить комментарий