Redux小白学习笔记
Redux小白学习笔记
Redux
本篇学习笔记是针对自己的项目所写的,所以有看不懂的地方要或者更多的注释和细节需要参加全栈小项目(react+redux+koa+mongo)中的(/client/src)部分,欢迎点赞支持~
简介
首先关于react中redux环境的搭建:cnpm i redux react-redux redux-thunk
这三个分别依赖一般是都要安装的,
第一个不说了,
第二个是关联react和redux的桥梁,大致原理是通过一个闭包生成一个数据中心store,然后把这个store绑定到React的顶层props里面,子组件通过HOC建立与顶层props.store的联系,进而获取数据、修改数据、更新UI
第三个是为了解决异步问题。
首先挂一下阮一峰老师的图片
- 用户通过component即view层触发事件,事件逻辑中遇到state改变就调用dispatch分发Action给store
- Store 调用 Reducer,并向Reducer传入两个参数:当前 State 和收到的 Action 对象
- Reducer中进行判断后生成新state再次转发给store,store提交新state给component接收
- component接收到改变的state后自动重新渲染
其实如果说子组件不涉及交互功能,只是单纯的数据展示的话,那么没必要用redux,直接父组件用redux,然后将属性传递给子组件就好
Store
首先创建Store.js文件,Store就是保存数据的地方,利用createStore()生成,整个应用要保持Store的唯一性。
createStore()中有三个参数:reducer, initialState, enhancer。
reducer :function 类型。一个传入 current state (当前state) 和 要处理的 action ,返回新的 state tree 的函数。
initialState:可以是任何类型。初始的state。如果你使用 combineReducers 去生产根 reducer 函数,它必须是一个与 combineReducer 的键相同的对象。
enhancer:function 类型。store 的增强器。你可以选择指定它来增加具有第三方第三方能力的 store。唯一一个跟 Redux 一起使用的 enhancer 是 applyMiddleware()
action
创建actions文件夹,其中按照事件的类型进行分类创建Action.js
其中最重要的是描述view层发出的通知,通俗的说就是事件中代码逻辑的主要书写场所,最终的目的是dispatch出一个action对象(action对象是一个用于描述已发生事件的普通JS对象,必须携带type属性)
当action对象被发出时,就会被State送给Reducer自动进行状态的更新。
Reducer 函数不用手动调用,store.dispatch方法会触发 Reducer 的自动执行。为此,Store 需知道Reducer,做法就是在createStore时,传入Reducer
Reducer
创建Reducer文件夹,其中按照事件的类型进行分类创建Reducer.js
其中最重要的是根据action对象携带的type来返回不同的State实现对state的更新,值得注意的是Reducer是一个纯函数(一种编程概念),意味着同样的输入,必定得到同样的输出。
{ // for example,纯函数内不能修改state,必须返回一个全新的对象
...state,
posts: state.posts.map(post => // 这样可以不修改state.posts的属性,而是直接返回新对象
post._id === action.payload._id ? { ...post, likes:action.payload.likes} : post )
}
最好把 State 对象设成只读。你没法改变它,要得到新的 State,唯一办法就是生成一个新对象。这样的好处是,任何时候,与某个 View 对应的 State 总是一个不变的对象。
利用**combineReducers()**可以产生一个整体的 Reducer 函数。该函数根据 State 的 key 去执行相应的子 Reducer,并将返回结果合并成一个大的 State 对象
React-Redux
它是redux作者封装的一个库,是一个第三方的模块,对Redux进一步的封装简化,提供了一些额外的API(例如:Provider,connect等),使用它可以更好的组织和管理我们的代码,遵循一定的组件拆分规范,在React中更方便的使用Redux
connect
connect()负责将UI组件(只是展示)与容器组件(只是状态管理)进行连接,
在UI组件内最后导出export default connect(mapStateToProps, mapDispatchToProps)(UI组件)
connect()接受两个参数:mapStateToProps和mapDispatchToProps。它们定义了 UI 组件的业务逻辑。前者负责输入逻辑,即将state映射到 UI 组件的参数(props),后者负责输出逻辑,即将用户对 UI 组件的操作映射成 Action
connect的两个参数都可以根据需求分别省略:
省略mapStateToProps,组件将不会监听 Redux store。UI 组件就不会订阅Store,但会更新Store,就是说Store的更新不会引起UI组件的更新
省略mapDispatchToProps,默认情况下dispatch会注入到你的组件props中,但只是订阅Store不涉及更新。
mapStateToProps
直白点的理解就是需要拿什么数据
mapStateToProps()作用就是像它的名字那样,建立一个从外部state对象到UI 组件的props对象的映射关系,写法如下
const mapStateToProps = state => ({
profile: state.profile
})
上面的profile为UI组件内需要的数据名称,它们将会被挂载到props对象上,通过props.profile访问。state.profile即reducer函数返回的结果
mapStateToProps会订阅 Store,每当外部state更新时,就重新计算组件参数,触发组件重新render()
注意当外部state映射到props上后,又赋值给内部独立的state时,要在componentWillReceiveProps()中监听props的改变后,再将props上的数据通过setState更新状态
要注意componentWillReceiveProps未触发的原因可能是因为父组件未进行深拷贝
mapDispatchToProps
需要改什么数据
mapDispatchToProps可以是一个对象,也可以是一个函数(返回对象),用来建立 UI 组件的参数到store.dispatch方法的映射
如果mapDispatchToProps是一个函数,会得到dispatch和ownProps(容器组件的props对象)两个参数
如果mapDispatchToProps是一个对象,它的每个键名也是对应 UI 组件的同名参数,键值应该是一个函数
Provider
在app.js中使用Provider组件可以简洁的让子组件直接拿到state,其原理是context属性
在利用hooks代替redux时,也是利用context属性的原理传递state
redux-thunk
thunk为解决异步action而生
applyMiddleware是 Redux 的原生方法,作用是将所有中间件组成一个数组,依次执行
在app.js文件中进行配置后action.js中的方法就可以通过接收dispatch参数去发送异步的action
export const addPost = postData => dispatch => {
axios.post("/api/posts", postData)
.then(res =>
dispatch({
type: ADD_POST,
payload: res.data
})
)
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
)
}
action creator
Action creator的设计也是由Flux架构来的产物,它是一种辅助用的函数,用来创建Action的。但因为设计的不同,在Redux中的Action creator比在Flux更简单,它通常只用来返回Action对象而已,当然它本身是个函数,在返回前是可以再针对返回的动作数据先进行运算或整理的,例如像下面这样的函数
经过redux-devtool调试后,发现还是不对!!!最后只能通过dispatch去派发(dispatch嵌套dispatch也行),return不起作用
http://echizen.github.io/tech/2016/07-23-dispatch
1. 直接return
export function fetchPosts(reddit) {
return {
type: REQUEST_POSTS,
reddit
}
}
2. 利用dispatch
export function fetchPosts(reddit) {
return dispatch => { // 函数柯里化写法
return dispatch({ // dispatch返回值就是action,当然不return也行
type: REQUEST_POSTS,
reddit
})
}
}
不懂可以看github,都有相应的注释~