React-Native + Redux Toolkit快速入门实践

1,094 阅读3分钟

前言

Redux Tookit 是官方出的 redux 工具,这里简单说一下使用的方法。

下文直接使用的是的 Typescirpt 的写法。

传送门

安装

yarn add @reduxjs/toolkit
yarn add react-redux

使用

新建目录结构如下:

├── src
│   ├── store
│   │   ├── slices
│   │   │   ├── counterSlice.ts
│   │   ├── hooks.ts
│   │   ├── store.ts
│   ├── App.tsx


创建 store

// src/store/store.ts
import {configureStore} from '@reduxjs/toolkit';

export const store = configureStore({
  reducer: {},
});

使用 store

在入口文件最外层添加代码:

// src/App.tsx
import {Provider} from 'react-redux';
import {store} from '@store/store';

const App = () => {
  return (
    <Provider store={store}>
    </Provider>
  );
}

export default App;

创建 slice

// src/store/slices/counterSlice.ts
import {createSlice, PayloadAction} from '@reduxjs/toolkit';
import {RootState} from '../store';

// 初始状态类型
interface CounterState {
  value: number;
}

// 定义一个初始状态
const initialState: CounterState = {
  value: 0,
} as CounterState;

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: state => {
      // Redux Toolkit 内置 Immer 库,可以直接修改 state
      state.value += 1;
    },
    decrement: state => {
      state.value -= 1;
    },
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload;
    },
  },
});
// 每个 case reducer 函数会生成对应的 Action creators
export const {increment, decrement, incrementByAmount} = counterSlice.actions;

export default counterSlice.reducer;

将 slice 加入到 store

// src/store/store.ts
import {combineReducers, configureStore} from '@reduxjs/toolkit';
import counterSlice from './slices/counterSlice';

const rootReducer = combineReducers({
  counter: counterSlice,
  // 有新的 slice 就往这里加
});

export const store = configureStore({
  reducer: rootReducer,
});

派发 action

先加入相关的 ts 类型:

// src/store/store.ts
// 省略其他代码

// 从 store 中推断出 `RootState` 和 `AppDispatch` 的类型
export type RootState = ReturnType<typeof store.getState>;
// 推断出类型: {counter: CounterState}
export type AppDispatch = typeof store.dispatch;

导出新的 hook:

// src/store/hooks.ts
import {useDispatch, useSelector} from 'react-redux';
import type {TypedUseSelectorHook} from 'react-redux';
import type {RootState, AppDispatch} from './store';

// 用下面的带类型的方法替换 `useDispatch` 和 `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

调用:

// src/App.ts
import {Button, Text, View} from 'react-native';
import React from 'react';
import {decrement, increment} from '@store/slices/counterSlice';
import {useAppDispatch, useAppSelector} from '@store/hooks';

const App = () => {
  const count = useAppSelector(state => state.counter.value);
  const dispatch = useAppDispatch();

  return (
   <Provider store={store}>
      <View>
          <Button title="增加" onPress={() => dispatch(increment())} />
          <Text>{count}</Text>
          <Button title="减少" onPress={() => dispatch(decrement())} />
        </View>
    </Provider>
  );
};

export default App;

处理异步 action

redux-tookit 有内置处理异步的中间件 createAsyncThunk:

// src/store/slice/counterSlice.ts
import {createAsyncThunk, createSlice, PayloadAction} from '@reduxjs/toolkit';

// 异步处理函数:
export const incrementDelay = createAsyncThunk(
  'counter/incrementDelay',
  async (payload: number) => {
    return new Promise<number>(resolve => {
      setTimeout(() => {
        resolve(payload);
      }, 1000);
    });
  },
);

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: state => {
      // Redux Toolkit 内置 Immer 库,可以直接修改 state
      state.value += 1;
    },
    decrement: state => {
      state.value -= 1;
    },
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload;
    },
  },
  // 将异步函数回调加入slice
  extraReducers: builder => {
    builder
      // incrementDelay fulfilled后会触发这个函数
      .addCase(incrementDelay.fulfilled, (state, action) => {
        state.value += action.payload;
      })
      // incrementDelay pending 触发
      .addCase(incrementDelay.pending, (state, action) => {})
      // incrementDelay rejected 触发
      .addCase(incrementDelay.rejected, (state, action) => {});
  },
});

调用异步 action:

// src/App.tsx
import {incrementDelay} from '@store/slices/counterSlice';

// 省略其他代码
<Button title="延迟增加1" onPress={() => dispatch(incrementDelay(1))} />

持久化数据

加入依赖:

yarn add redux-persist
yarn add @react-native-async-storage/async-storage

修改 store.ts:

// src/store/store.ts
import {combineReducers, configureStore} from '@reduxjs/toolkit';
import counterSlice from './slices/counterSlice';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {
  persistStore,
  persistReducer,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from 'redux-persist';

// 持久化配置
const persistConfig = {
  key: 'root',
  version: 1, // 持久化数据版本
  whitelist: ['counter'], // 需要持久化的 slice 名称
  storage: AsyncStorage, // 使用 AsyncStorage 作为持久化存储的仓库
};

const rootReducer = combineReducers({
  counter: counterSlice,
});

const persistedReducer = persistReducer(persistConfig, rootReducer);

export const store = configureStore({
  reducer: persistedReducer, // 替换为持久化后的reducer
  middleware: getDefaultMiddleware => {
    const defaultMiddleware = getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    });
    return defaultMiddleware;
  },
});

export const persistor = persistStore(store);

修改 App.tsx:

// src/App.tsx
import React from 'react';
import {Provider} from 'react-redux';
import {persistor, store} from '@store/store';
import {PersistGate} from 'redux-persist/integration/react';

const App = () => {
  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        ...
      </PersistGate>
    </Provider>
  );
};

export default App;

使用 Flipper 调试 redux

react-native 使用 Flipper 工具调试 redux 的时候需要装一个中间件。

加入依赖:

yarn add -D react-native-flipper
yarn add -D redux-flipper

加入中间件:

export const store = configureStore({
  reducer: persistedReducer,
  middleware: getDefaultMiddleware => {
    const defaultMiddleware = getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    });
    // 开发模式的时候加入中间件
    if (__DEV__) {
      const createDebugger = require('redux-flipper').default;
      return defaultMiddleware.concat(createDebugger());
    }
    return defaultMiddleware;
  },
});

然后在 Flipper 下载 redux 插件即可查看。

❤️ 支持

如果本文对你有帮助,点赞 👍 支持下我吧,你的「赞」是我创作的动力。