Open Skeanmy opened 4 years ago
产生原因:单页应用需要管理大量的状态
核心特点:
state 这个对象没有修改器方法,即setter方法
要更改state中的数据,需要发起一个action,action是一些普通的js对象,用于描述发生了什么
{ type: 'ADD_TODO', text: 'Go to swimming pool' } { type: 'TOGGLE_TODO', index: 1 } { type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }
action与state串起来即为reducer,即reducer是一个接收state与action,并且返回新的state的函数
三大特点:
单一数据源
整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。
让同构应用开发变得容易,来自于服务端的state可以很方便的序列化注入到客户端中
state是只读的,唯一改变state的方法是触发action
视图与网络请求不能直接修改state,只能表达要修改的意图,所有的修改被集中化处理,不会出现race condition
浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存
浅拷贝只拷贝一层,对象拷贝其引用,基本类型拷贝其值
深拷贝:会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象
Object.assign(target, ...sources);
Reducer必须是纯函数
如果函数的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部任何状态或数据的变化,必须只依赖于其输入参数。 纯函数非常“靠谱”,执行一个纯函数你不用担心它会干什么坏事,它不会产生不可预料的行为,也不会对外部产生影响。
如果函数的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部任何状态或数据的变化,必须只依赖于其输入参数。
纯函数非常“靠谱”,执行一个纯函数你不用担心它会干什么坏事,它不会产生不可预料的行为,也不会对外部产生影响。
reducer内不要做这些事情:
修改传入参数;
执行有副作用的操作,如 API 请求和路由跳转;
调用非纯函数,如 Date.now() 或 Math.random()。
Date.now()
Math.random()
function todoApp(state = initialState, action) { switch (action.type) { case SET_VISIBILITY_FILTER: return Object.assign({}, state, { visibilityFilter: action.filter }) default: return state } }
使用 Object.assign() 新建了一个副本。不能这样使用 Object.assign(state, { visibilityFilter: action.filter }),因为它会改变第一个参数的值。你必须把第一个参数设置为空对象。你也可以开启对ES7提案对象展开运算符的支持, 从而使用 { ...state, ...newState } 达到相同的目的。
Object.assign()
Object.assign(state, { visibilityFilter: action.filter })
{ ...state, ...newState }
store里面有需要的状态,就直接从store中取出来,没有的话会去reducer里面去找
写代码前先想一下state这个对象的结构,如何才能以最简的形式把应用的 state 用对象描述出来
用户发出 action,action是数据的唯一来源
store.dispatch(action);
action
action函数:作用仅仅是简单的返回一个action,这样容易移植与测试
// actionCreator.js import { CHANGE_INPUT } from './actionTypes'; // 如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。 export const changeInputAction = (value)=>({ type: CHANGE_INPUT, value })
然后,Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action。 Reducer 会返回新的 State 。
let nextState = todoApp(previousState, action); (previousState, action) => newState
State 一旦有变化,Store 就会调用监听函数。
// 设置监听函数 store.subscribe(listener); function listerner() { let newState = store.getState(); // component 就是 this component.setState(newState); }
getState()
dispatch(action)
subscribe(listener)
todolist删除时有问题
todolist
<List bordered dataSource={this.props.list} renderItem={(item,index)=>(<List.Item onClick={(index)=>{this.props.deleteItem(index)}}>{item}</List.Item>)} />
主要是我们的index出现了重新声明的问题。onClick箭头函数接收到的参数是事件对象e不是我们需要的index
index
onClick
e
<List bordered dataSource={this.props.list} renderItem={(item,index)=>(<List.Item onClick={()=>{this.props.deleteItem(index)}}>{item}</List.Item>)} />
// index.js import { createStore } from 'redux' // 引入createStore方法 import reducer from './reducer' const store = createStore(reducer) // 创建数据存储仓库 export default store //暴露出去 // reducer.js const defaultState = {} //默认数据 export default (state = defaultState,action)=>{ //就是一个方法函数 return state }
Provider提供器
Provider
只要使用了这个组件,组件里边的其它所有组件都可以使用store了
store
connect连接器
connect
import {connect} from 'react-redux' //引入连接器 export default connect(xxx, null)(TodoList);
映射关系是把原来state映射成为组件中的props属性
const mapDispatchToProps = dispatch => { return { onTodoClick: id => { dispatch(toggleTodo(id)) // 派发一个actions,直通reducer(原理图) } }; }; const FilterLink = connect( mapStateToProps, // 状态映射 mapDispatchToProps // 方法映射 )(Link); export default FilterLink;
多做UI组件,即无状态组件
connect的作用是把UI组件(无状态组件)和业务逻辑代码的分开,然后通过connect再链接到一起,让代码更加清晰和易于维护。这也是React-Redux最大的优点。
React-Redux
import { connect } from 'react-redux'; import { setVisibilityFilter } from '../store/actions'; import Link from '../components/Link'; // UI组件 const mapStateToProps = (state, ownProps) => { return { active: ownProps.filter === state.visibilityFilter }; }; const mapDispatchToProps = (dispatch, ownProps) => { return { onClick: () => { dispatch(setVisibilityFilter(ownProps.filter)) } }; }; const FilterLink = connect( mapStateToProps, mapDispatchToProps )(Link); export default FilterLink;
dispatch一个action之后,到达reducer之前,进行一些额外的操作,就需要用到middleware。
你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。换言之,中间件都是对store.dispatch()的增强
import { applyMiddleware, createStore } from 'redux'; import thunk from 'redux-thunk'; const store = createStore( reducers, applyMiddleware(thunk) );
applyMiddleware
applyMiddleware是Redux的一个原生方法,将所有中间件组成一个数组,依次执行。
const store = createStore( reducers, applyMiddleware(thunk, logger) );
redux-thunk最重要的思想,就是可以接受一个返回函数的action creator。如果这个action creator 返回的是一个函数,就执行它,如果不是,就按照原来的next(action)执行。 正因为这个action creator可以返回一个函数,那么就可以在这个函数中执行一些异步的操作。
//异步的action, 由于使用了redux-thunk的thunk中间件, //所以,在这个action里不用像同步action那样,必须返回一个对象,在这里返回一个方法 //这个方法有一个dispatch的参数,这个dispatch就是store里的dispatch. export const addAsync = (num = 1) => { return (dispatch) => { // 当这个方法刚进来的时候,就马上告诉reducer,我要开始获取数据了, // reducer接收到这个动作,就会执行相应的操作(把isLoading改为true,看reducer里的代码) dispatch({ type: START_GET_DATA }); // 用setTimeout来模拟获取数据 setTimeout(() => { // 获取数据完成之后,需要dispatch两个action. // 一个是把获取到的数据,传到一个动作里(ADD) dispatch({ type: ADD, num }); // 这个是用来告诉reducer,我获取数据成功了。reducer接收到这个动作, // 就会执行相应的操作(把isLoading改为false,看reducer里的代码) dispatch({ type: GET_DATA_SUCCESS }); }, 2000) } }
@Skeanmy 图片挂了
Redux
基础
产生原因:单页应用需要管理大量的状态
核心特点:
state 这个对象没有修改器方法,即setter方法
要更改state中的数据,需要发起一个action,action是一些普通的js对象,用于描述发生了什么
action与state串起来即为reducer,即reducer是一个接收state与action,并且返回新的state的函数
三大特点:
单一数据源
让同构应用开发变得容易,来自于服务端的state可以很方便的序列化注入到客户端中
state是只读的,唯一改变state的方法是触发action
深浅拷贝复习
浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存
浅拷贝只拷贝一层,对象拷贝其引用,基本类型拷贝其值
深拷贝:会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象
Reducer必须是纯函数
reducer内不要做这些事情:
修改传入参数;
执行有副作用的操作,如 API 请求和路由跳转;
调用非纯函数,如
Date.now()
或Math.random()
。工作流程
store里面有需要的状态,就直接从store中取出来,没有的话会去reducer里面去找
写代码前先想一下state这个对象的结构,如何才能以最简的形式把应用的 state 用对象描述出来
用户发出 action,action是数据的唯一来源
action
action函数:作用仅仅是简单的返回一个action,这样容易移植与测试
然后,Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action。 Reducer 会返回新的 State 。
State 一旦有变化,Store 就会调用监听函数。
getState()
方法获取 state;dispatch(action)
方法更新 state;subscribe(listener)
注册监听器;subscribe(listener)
返回的函数注销监听器。小坑
todolist
删除时有问题主要是我们的
index
出现了重新声明的问题。onClick
箭头函数接收到的参数是事件对象e
不是我们需要的index
创建过程
React-redux
Provider
提供器只要使用了这个组件,组件里边的其它所有组件都可以使用
store
了connect
连接器映射关系是把原来state映射成为组件中的props属性
性能优化
多做UI组件,即无状态组件
redux中间件—redux-thunk
dispatch一个action之后,到达reducer之前,进行一些额外的操作,就需要用到middleware。
你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。换言之,中间件都是对store.dispatch()的增强
applyMiddleware
applyMiddleware
是Redux的一个原生方法,将所有中间件组成一个数组,依次执行。