Reducer是用于改变数据的函数

1.一个数据仓库,有且仅有一个reducer,并且通常情况下,一个工程只有一个仓库,因此,一个系统,只有一个reducer

2.为了方便管理,通常会将reducer放到单独的文件中。

// src/redux/reducer/index.js
import * as actionTypes from './action/action-type';
/**
 * reducer 本质上是一个普通函数
 * @param {*} state 之前仓库中的状态(数据)
 * @param {Object} action 要做什么,约定格式为 {type:"操作类型", payload:附加数据}
 */
export default function reducer(state, action) {
	//  返回一个新的状态
	if (action.type === actionTypes.INCREASE) {
		return state + 1;
	} else if (action.type === actionTypes.DECREASE) {
		return state - 1;
	} else if (action.type === actionTypes.SET) {
		return action.payload;
	} else {
		// 如果是一个无效的操作类型,数据不变
		return state;
	}
}
// src/redux/index.js
import { createStore, bindActionCreators } from 'redux';
import * as numberActions from './action/number-action';
import reducer from './reducer';
// 初始值为10
const store = createStore(reducer, 10);

3.reducer被调用的时机

①.通过store.dispatch,分发了一个action,此时,会调用reducer

②.当创建一个store的时候,会调用一次reducer,主要是为了初始化

  • 可以利用这一点,用reducer初始化状态
  • 创建仓库时,不传递任何默认状态
  • 将reducer的参数state设置一个默认值
// src/redux/reducer/index.js
import * as actionTypes from './action/action-type';
/**
 * reducer 本质上是一个普通函数
 * @param {*} state 之前仓库中的状态(数据)
 * @param {Object} action 要做什么,约定格式为 {type:"操作类型", payload:附加数据}
 */
export default function reducer(state=10, action) {
	//  返回一个新的状态
	if (action.type === actionTypes.INCREASE) {
		return state + 1;
	} else if (action.type === actionTypes.DECREASE) {
		return state - 1;
	} else if (action.type === actionTypes.SET) {
		return action.payload;
	} else {
		// 如果是一个无效的操作类型,数据不变
		return state;
	}
}
// src/redux/index.js
import { createStore, bindActionCreators } from 'redux';
import * as numberActions from './action/number-action';
import reducer from './reducer';
// 初始值为10
const store = createStore(reducer);

4.reducer内部通常使用switch来判断type值

// src/redux/reducer/index.js
import * as actionTypes from '../action/action-type';
/**
 * reducer 本质上是一个普通函数
 * @param {*} state 之前仓库中的状态(数据)
 * @param {Object} action 要做什么,约定格式为 {type:"操作类型", payload:附加数据}
 */
export default function reducer(state = 10, action) {
	console.log('reducer被调用了', state, action);
	//  返回一个新的状态
	switch (action.type) {
		case actionTypes.INCREASE:
			return state + 1;
		case actionTypes.DECREASE:
			return state - 1;
		case actionTypes.SET:
			return action.payload;
		// 如果是一个无效的操作类型,数据不变
		default:
			return state;
	}
}

5.reducer必须是一个没有副作用的纯函数

为什么需要是纯函数

a.纯函数有利于测试和调试

b.有利于还原数据

c.有利于将来与react结合时的优化

具体要求

a.不能改变参数,因此若要让状态变化,必须得到一个新的状态

b.不能有异步

c.不能对外部环境造成影响

import * as actionTypes from '../action/action-type';
/**
 * reducer 本质上是一个普通函数
 * @param {*} state 之前仓库中的状态(数据)
 * @param {Object} action 要做什么,约定格式为 {type:"操作类型", payload:附加数据}
 */
export default function reducer(state = { name: 'jerry', age: 12 }, action) {
	// state为对象时,返回一个新的状态
	switch (action.type) {
		case actionTypes.INCREASE:
			return { ...state, age: state.age + 1 };
            // return Object.assign({}, state, { age: state.age + 1 });
		case actionTypes.DECREASE:
			return state - 1;
		case actionTypes.SET:
			return action.payload;
		// 如果是一个无效的操作类型,数据不变
		default:
			return state;
	}
}

6.由于在大中型项目中,操作比较复杂,数据结构也比较复杂,因此,需要对reducer进行细分。

①.redux提供了方法,可以帮助我们更加方便的合并reducer(vscode快捷创建reducer方式:rxreducer)

//src/redux/reducer/loginUser.js
import { SET_LOGIN_USER_TYPE } from '../action/loginuser-action';
const initialState = null;
// 当前登录用户的reducer
export default (state = initialState, { type, payload }) => {
	switch (type) {
		case SET_LOGIN_USER_TYPE:
			return payload;
		default:
			return state;
	}
};
//src/redux/reducer/users.js
import * as usersAction from '../action/users-action';
import uuid from 'uuid';
const initialState = [
	{ id: uuid(), name: '用户1', age: 11 },
	{ id: uuid(), name: '用户2', age: 12 },
];
// 所有登录用户的reducer
export default (state = initialState, { type, payload }) => {
	switch (type) {
		case usersAction.ADD_USER:
			return [...state, payload];
		case usersAction.DELETE_USER:
			return state.filter((user) => user.id !== payload.id);
		case usersAction.UPDATE_USER:
			// id存在则替换成payload对象,否则的话用原来的对象
			return state.map((user) => (user.id === payload.id ? {...user, ...payload} : user));
		default:
			return state;
	}
};
// src/redux/reducer/index.js
import loginUserReducer from './loginUser';
import usersReducer from './users';

export default (state = {}, action) => {
    // 将不同的reducer合并到一处进行管理
	const newState = {
		loginUser: loginUserReducer(state.loginUser, action),
		users: usersReducer(state.users, action),
	};
	return newState;
};

②.combineReducers: 合并reducer,得到一个新的reducer,该新的reducer管理一个对象,该对象中的每一个属性交给对应的reducer管理。

reducer树形结构

import loginUserReducer from './loginUser';
import usersReducer from './users';
import { combineReducers } from 'redux';

// export default (state = {}, action) => {
// 	const newState = {
// 		loginUser: loginUserReducer(state.loginUser, action),
// 		users: usersReducer(state.users, action),
// 	};
// 	return newState;
// };

// 相当于 5-11 行的代码
export default combineReducers({
	loginUser: loginUserReducer,
	users: usersReducer,
});