# React-base-react-redux **Repository Path**: lisa_zhu2012/React-base-react-redux ## Basic Information - **Project Name**: React-base-react-redux - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-02-22 - **Last Updated**: 2020-12-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # React-base-redux #### 介绍 了解redux在react里的基础运用 #### 软件架构 软件架构说明 #### 项目搭建及上传gitee 1. npm install create-react-app -g 2. create-react-app react-project 安装的时候提示我node版本过低 (npm install -g n) 3. cd react-project npm install 4. npm run eject(当我们要进行二次配置的时候,需要找到node_modules文件夹里的react-scripts进行配置,但是当我们执行**npm run eject**就可以将配置文件抽出,方便开发配置) 5. npm run start 6. git init 7. git remote add origin https://gitee.com/lisa_zhu2012/react-project.git 8. git add . / git commit -m '' / git push -u origin master (or git push --set-upstream origin master) #### 项目依赖下载 1. npm install node-sass -D 2. npm install redux -S #### [redux 基础知识](http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html) ![redux](./public/redux.jpg) React 只是 DOM 的一个抽象层,并不是 Web 应用的完整解决方案。有两个方面,它没涉及。 * 代码结构 * 组件之间的通信 > 2014年 Facebook 提出了 Flux 架构的概念,引发了很多的实现。2015年,Redux 出现,将 Flux 与函数式编程结合一起,很短时间内就成为了最热门的前端架构。 **如果你不知道是否需要 Redux,那就是不需要它** **只有遇到 React 实在解决不了的问题,你才需要 Redux** 简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。 * 用户的使用方式非常简单 * 用户之间没有协作 * 不需要与服务器大量交互,也没有使用 WebSocket * 视图层(View)只从单一来源获取数据 需要使用redux的项目: * 用户的使用方式复杂 * 不同身份的用户有不同的使用方式(比如普通用户和管理员) * 多个用户之间可以协作 * 与服务器大量交互,或者使用了WebSocket * View要从多个来源获取数据 > 上面这些情况才是 Redux 的适用场景:多交互、多数据源。 从组件层面考虑,什么样子的需要redux: * 某个组件的状态,需要共享 * 某个状态需要在任何地方都可以拿到 * 一个组件需要改变全局状态 * 一个组件需要改变另一个组件的状态 redux的设计思想: 1. Web 应用是一个状态机,视图与状态是一一对应的。 2. 所有的状态,保存在一个对象里面(唯一数据源)。 ##### redux的流程: 1.store通过reducer创建了初始状态 2.view通过store.getState()获取到了store中保存的state挂载在了自己的状态上 3.用户产生了操作,调用了actions 的方法 4.actions的方法被调用,创建了带有标示性信息的action 5.actions将action通过调用store.dispatch方法发送到了reducer中 6.reducer接收到action并根据标识信息判断之后返回了新的state 7.store的state被reducer更改为新state的时候,store.subscribe方法里的回调函数会执行,此时就可以通知view去重新获取state > 注意:flux、redux都不是必须和react搭配使用的,因为flux和redux是完整的架构,在学习react的时候,只是将react的组件作为redux中的视图层去使用了。 reducer必须是一个纯函数: **Reducer 函数最重要的特征是,它是一个纯函数。也就是说,只要是同样的输入,必定得到同样的输出。** 纯函数是函数式编程的概念,必须遵守以下一些约束。 * 不得改写参数 * 不能调用系统 I/O 的API * 不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果 由于 Reducer 是纯函数,就可以保证同样的State,必定得到同样的 View。但也正因为这一点,Reducer 函数里面不能改变 State,必须返回一个全新的对象,请参考下面的写法。 ``` // State 是一个对象 function reducer(state, action) { return Object.assign({}, state, { thingToChange }); // 或者 return { ...state, ...newState }; } // State 是一个数组 function reducer(state, action) { return [...state, newItem]; } ``` 最好把 State 对象设成只读。你没法改变它,要得到新的 State,唯一办法就是生成一个新对象。这样的好处是,任何时候,与某个 View 对应的 State 总是一个不变的对象。 我们可以通过在createStore中传入第二个参数来设置默认的state,但是这种形式只适合于只有一个reducer的时候 ### redux 详细开发流程及扩展 1. 下载redux工具 **npm i redux -S** 2. 创建store const store = createStore(reducer) 3. 创建reducer纯函数 ``` const reducer = (state = _state, action) => { let new_state = Object.assign({}, state) switch ( action.type ) { case ADD_NEW_TODO: new_state.todos.push(action.todo);break; case REMOVE_TODO: new_state.todos = action.todos;break; default:break; } //同步一下本地存储 localStorage.todos = JSON.stringify(new_state.todos) //reducer一定要返回状态 return new_state } export default reducer ``` 4. 为store挂载默认状态 为reducer的state参数设置默认值,再返回出新的state,这样的话,store就有state了 5. 组件使用store的state 组件通过调用store.getState()来获得store中的state 6. 创建actionCreator actionCreator里的方法,作用是执行一些自定逻辑之后,创建一个带有标识性信息的action,交由reducer处理 store.dispatch(action) 7. 在reducer中,根据action上的标识信息做出判断之后,返回一个新状态,这个时候store里的状态已经更改了 8. 让组件去获取最新的状态 在组件的初始化阶段的生命周期钩子函数中给store.subscribe传入回调函数,当状态更改的时候这个回调函数就会触发,在这个回调里就可以让组件获取最新的状态之后进行setState,当然,如果发现所用的状态没有更改可以做出判断来决定是否进行setState #### reducer划分 当我们协同开发的时候,或者项目独立功能模块较多的时候,把状态放在一个reducer中处理的话会导致更新维护比较麻烦 在这里我们研究将store进行模块化的管理 actionCreator、state本身与store耦合度很低,最主要的是把reducer拆分开 我们可以利用combindReducers函数,将分离开的renducer整合成一个,这样的话,需要注意的是在使用的时候,state也会根据划分的reducer有一个不同的分布(因为一个应用中只能有一个大的state,这样的话reducer中的代码将会特别特别的多,那么就可以使用combineReducers方法将已经分开的reducer合并到一起) ``` import { combineReducers } from 'redux' //引入分开的reducer import todos from './todos/reducer' //将分开的reducer合并在一起,形成一个整体的reducer const reducer = combineReducers({ todos }) export default reducer ``` 注意: 1. 分离reducer的时候,每一个reducer维护的状态都应该不同 2. 通过store.getState获取到的数据也是会安装reducers去划分的 3. 划分多个reducer的时候,默认状态只能创建在reducer中,因为划分reducer的目的,就是为了让每一个reducer都去独立管理一部分状态 ### react-redux 这是一个好东西! 对比redux与vue中的vuex,vuex要比redux用起来简单、方便! 因为vuex是vue的一个工具、插件,与vue的耦合度高,所以里面很多东西作者已经给我们封装好了 但是redux不只是react可以用,很多地方都能去用,所以在react中使用redux的时候,很多东西都需要我们自己写~ 麻烦的地方: 1. 组件获取状态较为麻烦 2. 状态更新之后,组件需要手动的获取最新状态 3. 组件使用actionCreator的方法也不是很方便 所以现在学习使用react-redux工具,这个工具是准备将react和redux连接起来的 下载 **npm i react-redux -S** 在react-redux中,有一个概念: 组件应该划分一下类别:**容器组件(智能组件)、UI组件(木偶组件)** 这样的话,任何一个组件都可以分离成一个容器组件和一个UI组件的组合 容器组件去和store进行交互,获取状态...然后再将这些东西传递给UI组件,UI组件从属性里接收基于可以了 容器组件可以利用react-redux去根据现有的UI组件去自动生成 也就是说只是要需要和store进行交互的组件,我们就将其处理成容器组件和UI组件的结合,我们只需要写UI组件就可以了,容器组件会自动生成的 使用方法: 1. 在根组件外部包裹上Provider组件,并为其传入store 目的,让Provider里面的所有的容器组件都可以使用到store里的东西 Provider是通过context属性将自己的东西传递到内部子级组件中的 2. 把需要使用到全局状态的组件处理成容器组件和UI组件 ContainerComponnet = connect()(UIComponent) 让容器组件将自己context里的store相关的东西传递给UI组件 3. actionCreator的方法只负责创建对应的action就可以了,无需再去dispatch 4. 现在要让组件去调用store.dispatch,也就是说让组件得到store.dispatch的方法,这也属性在使用store的东西,这个时候也要生成一个容器组件 传入mapDispatchToProps方法可以将一些方法传入到UI组件的属性上,而这些方法都能调用到dispatch,将actionCreator创建好的action传入到dispatch里就可以了 这个函数会接收store.dispath,返回的对象上的方法会放入到UI组件的属性上 5. 可以利用redux中bindActionCreators将actionCreator的方法处理一下产生新方法,在新方法里已经自动的将原方法里产生action给dispatch了 bindActionCreators会返回一个对象,这个对象里的方法其实就是actionCreator里的方法处理之后的结果,处理的情况:将原方法中创建的action直接dispatch走 ``` export default connect(state => state,dispatch=>{ return bindActionCreators(actionCreator, dispatch) })(Control) ``` 6. 这个时候,actionCreator变得纯粹了很多,不用去dispatch,专注的返回action就可以了,但是,如果我们有异步动作的话,现在放在action里直接不生效了 在这里,我们使用redux的中间件来处理,redux的中间件有很多:redux-thunk、redux-promise、redux-saga...... 在这里我们学习使用redux-thunk #### redux-thunk的使用方法 1. **npm i redux-thunk -S** 2. 将thunk中间在在创建store的时候加入进去 import { createStore, applyMiddleware } from 'redux' import thunk from 'redux-thunk' import reducer from './reducer' const store = createStore(reducer, applyMiddleware(thunk)) 3. actionCreator里的方法就可以返回一个函数。这个函数会接收到dispatch 所以,如果有异步的动作,就在对应的actionCreator的方法里返回一个接收到dispatch的函数,在这个函数中创建action再手动的dispatch