Redux在项目中的使用

一、Redux核心概念

1、state

(1)作用:存储数据

(2)注意:Redux不负责驱动视图,只是负责计算数据、保存数据

2、action

(1)本质:具体type字段的JS对象;

(2)作用:描述一个动作;

3. dispatch

(1)作用:触发一个action

(2)特点:redux中修改state唯一的方式就是dispatch(Action)

4. reducer

(1)本质:纯函数

(2)作用:负责计算新的状态(数据)

(3)注意:

      ①不可变数据,需新值覆盖旧值

      ②不能写请求、操作DOM

二、Redux在项目中使用(js版)

1.安装redux

npm i redux

2.React-Redux插件

   作用:简化Redux在React中的使用

npm i react-redux

3.创建store仓库文件结构,大致如下:

src
├─store
    └─reducer            
    │       count.js
    │       index.js      // 入口文件合并多个 reducer
    ├─action
    │      actionTypes.js // actionType 提示文件
    │      count.js
    └─index.js           // store 入口文件

以一个count计算为例子:

4.在src/store/reducer/count.js创建一个reducer,在src/store/reducer/index.js合并所有reducer

const initState = { count: 100 }

export default function countReducer(state = initState, action) {

  switch (action.type) {
    case 'xxx':

    default:
      return state
  }
}
import { combineReducers } from 'redux';
import countReducer from './count';
import userReducer from './user';

const rootReducer = combineReducers({
  count: countReducer,
  user: userReducer,
});

export default rootReducer;

5.在src/store/index.js创建store:

import { legacy_createStore as createStore } from 'redux';
import rootReducer from './reducer';

const store = createStore(rootReducer);
export default store;

6.把仓库与项目关联起来(使用插件实现数据驱动视图)

在src/index.js中,加上Provider并关联store:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

7.在页面上获取数据:

使用useSelector获取store中的数据:

import { useSelector } from 'react-redux'

export default function App(){
   const count = useSelector(state => state.count)
   console.log(count)
}

8.修改仓库的数据(触发dispatch是修改数据的唯一方式):

(1)在src/store/count.js封装一个Action函数:

export const updateCountAction = () => {
  return {
    type: 'count/add',
    payload: null,
  };
};

(2)使用dispatch去触发:

import { updateCountAction } from './store/action/count.js'

export default function App(){
   const count = useSelector(state => state.count)
   //这是插件的dispatch
   const dispatch = useDispatch()

   return(
     <h1>{count}</h1>
     <button onClick={ ()=> dispatch(updateCountAction()) }>点击加1</button>
   )
}

(3)在reducer中计算数据:

import { legacy_createStore as createStore } from 'redux'

const initState = { count: 100 }

export default function countReducer(state = initState, action) {

  switch (action.type) {
+    case 'count/add':
+    return {
+     ...state,
+     count: state.count + 1
    }

    default:
      return state
  }
}

(4)优化:使用一个常量去代替type的字符串

1.在src/store/action/actionType.js中定义各个action中type的名字:

export const COUNT_ADD = 'count/add'

2.在action和reducer中分别导入使用:

action:

import { COUNT_ADD } from 'src/action/actionType.js'

export const updateCountAction = () => {
  return {
    type: COUNT_ADD,
    payload: null,
  };
};

reducer:

import { legacy_createStore as createStore } from 'redux'

+import { COUNT_ADD } from 'src/action/actionType.js'

const initState = { count: 100 }

export default function countReducer(state = initState, action) {

  switch (action.type) {
+   case COUNT_ADD:
    return {
     ...state,
     count: state.count + 1
    }

    default:
      return state
  }
}

9. 使用中间件redux-thunk发送异步请求

1.安装redux-thunk

npm i redux-thunk

2.导入到store/index.js, 并配置

import { applyMiddleware, legacy_createStore as createStore } from 'redux'

+ import thunk from 'redux-thunk'

// 将 thunk 添加到中间件列表中
- const store = createStore(rootReducer, applyMiddleware())
+ const store = createStore(rootReducer, applyMiddleware(thunk))

export default store

// 这里是安装调试工具redux-devtools-extension
// 1.安装 npm i redux-devtools-extension
// 2.修改 store
// const store = createStore(rootReducer,  composeWithDevTools(applyMiddleware(thunk)))

3.使用

import { COUNT_ADD } from 'src/action/actionType.js'

export const updateCountAction = () => {
	// 返回一个异步函数
+ 	return async (dispatch) => {    
+		const res = await loadNewAPI();    
		// 使用函数形参的dispatch,再次发起dispatch(action)
+		dispatch({ type: COUNT_ADD, payload: res });
+ 	};
};

三、Redux在项目中使用(ts版)

创建仓库的过程(1-6步)与js一样

不同点:

1.获取仓库的数据使用:useAppSelector()

(1)在创建仓库的时候加上这两句代码(插件官方的)

import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import { legacy_createStore as createStore } from 'redux';
import rootReducer from './reducer';

const store = createStore(rootReducer);
export default store;

// 获取仓库的数据
+export type RootState = ReturnType<typeof store.getState>;
+export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

(2)获取仓库的数据使用useAppSelector()

 const { count } = useAppSelector((state) => state.count);

2.修改数据dispatch使用:useAppDispatch() 

(1)在创建仓库的时候加上最后两句代码(插件官方的)

import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import { legacy_createStore as createStore } from 'redux';
import rootReducer from './reducer';

const store = createStore(rootReducer);
export default store;

// 获取仓库的数据
+export type RootState = ReturnType<typeof store.getState>;
+export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

// 约定action和reducer中的type
+export type AppDispatch = typeof store.dispatch;
+export const useAppDispatch = () => useDispatch<AppDispatch>();

(2)封装action函数

export const updateCountAction = (id: number) => ({
  type: 'list/updateCountAction',
  payload: id,
});

(3)使用useAppDispatch()去修改数据;

import { useAppDispatch, useAppSelector } from '../store';
import { updateCountAction } from '../store/action';

//使用
const dispatch = useAppDispatch();

//调用
<button onClick={() => {  dispatch(updateCountAction()) }}>

(4)reducer计算

import { legacy_createStore as createStore } from 'redux'

const initState = { 
count: 100,   
list: [
    { id: 1, task: '吃饭', isDone: true },
    { id: 2, task: '睡觉', isDone: true },
    { id: 3, task: '学习', isDone: false },
  ], }

export default function countReducer(state = initState, action) {
  switch (action.type) {
    case 'list/updateCountAction':
      return {
        ...state,
        count: state.count + 1
      }

    default:
      return state
  }
}

(5)类型约定(保证action和reducer中的type一致)

①在每个reducer的ts文件中去定义type的类型,并且绑定给action:

import { legacy_createStore as createStore } from 'redux'

const initState = { 
count: 100,   
list: [
    { id: 1, task: '吃饭', isDone: true },
    { id: 2, task: '睡觉', isDone: true },
    { id: 3, task: '学习', isDone: false },
  ], }

//第一个是更新reducer的type, 第二个是清除reducer的type
+export type ActionType = { type: 'list/updateById'; payload: number } | { type: 'list/clearDone' };

 // 在ts-react中,不要去解构action
-//export default function countReducer(state = initState, action) {
+export default function countReducer(state = initState, action: ActionType) {

  switch (action.type) {
    case 'list/updateCountAction':
      return {
        ...state,
        count: state.count + 1
      }

    default:
      return state
  }
}

②在封装action的函数中加上type

import { ActionType } from '../reducer/list';

export const updateByIdAction = (id: number): ActionType => ({
  type: 'list/updateById',
  payload: id,
});

export const clearDoneAction = (): ActionType => ({
  type: 'list/clearDone',
});

3.Redux指定reducer函数的返回值类型

import { legacy_createStore as createStore } from 'redux'

const initState = { 
count: 100,   
list: [
    { id: 1, task: '吃饭', isDone: true },
    { id: 2, task: '睡觉', isDone: true },
    { id: 3, task: '学习', isDone: false },
  ], }

//第一个是更新reducer的type, 第二个是清除reducer的type
+export type ActionType = { type: 'list/updateById'; payload: number } | { type: 'list/clearDone' };

 // 在ts-react中,不要去解构action
-//export default function countReducer(state = initState, action) {
-//export default function countReducer(state = initState, action: ActionType) {
+export default function countReducer(state = initState, action: ActionType): typeof initState {

  switch (action.type) {
    case '':
      return {
        ...state,
        count: state.count + 1
      }
    default:
      return state
  }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值