第一步
下面的文件都是在store中,利用模块化开发的思想
统一把变量放在actionTypes文件中
通过Redux的createStore方法来生成Store。createStore方法的参数是Reducer方法(可以用combinReducers方法将多个Reducer合并起来,将业务数据拆分的更清晰)。Reducer方法接收两个参数state和Action。生成完store对象后,需要用subscribe方法注册回调函数listener,当store内的state发生变化时会自动调用回调函数。回调函数内可以通过getState方法取得最新的state。
初始化完成后。用户要想修改Store里的state,只能通过dispatch方法,该方法接收Action作为参数。Reducer收到Action后,修改相应的state。进而触发初始化过程中注册的listener回调函数。
// 把整个应用程序中,所有的action,type都写在这里 action是给dispatch使用 type是给reducer使用
export const CHANGE_MSG='800'
// 下面是用action的增删改
export const Todo_ADD='Todo_ADD'
export const Todo_DEL='Todo_DELL'
export const Todo_UPD='Todo_UPD'
export const Todo_CLEAR='Todo_CLEAR'
// 封装actionType,如果有相同的变量,直接会报错,保证action Type是唯一的,不重突和重复
// 可以保证 action Type永远不会重复和冲突
// 给action的使用和reducer使用
在action中todo.js文件是,主要是定义一些方法
import {
Todo_ADD,
Todo_DEL,
Todo_UPD,
Todo_CLEAR
}
from '../actionTypes'
// action是复用的
export function addTodo(playload){
return{
type: Todo_ADD,
playload
}
}
export function delTodo(playload){
return{
type: Todo_DEL,
playload
}
}
export function updTodo(playload){
return{
type: Todo_UPD,
playload
}
}
export function clearTodo(playload){
return{
type: Todo_CLEAR,
playload
}
}
在redcers中todo.js
要操作的内容
import {
Todo_ADD,
Todo_DEL,
Todo_UPD,
Todo_CLEAR
}
from '../actionTypes'
let initState={
msg:'hello todo',
list:[
{id:1,task:'学习'},
{id:2,task:'看书'}
]
}
export default function reducer(state=initState,action){
// state只读的,所以需要深复制
let newState = JSON.parse(JSON.stringify(state))
// let newState=Object.assign({},state) 对象嵌套很深会出现问题 abc:{ac:{cde:{frt:{}}}}
// let newState={...state,list} 对象嵌套很深会出现问题 abc:{ac:{cde:{frt:{}}}}
switch(action.type){
case Todo_ADD:
newState.list.push(action.playload)
return newState
case Todo_DEL:
console.log('收到了',action)
// let newState1=JSON.parse(JSON.stringify(state))
// newState.list.splice((ele,idx,arr)=>{} 这种是错误的,会把所有的都删除
newState.list.map((ele,idx,arr)=>{
if(ele.id===action.playload){
arr.splice(idx,1);
}
return false // 箭头函数 不用return false eslint会报错
})
return newState // 初始化的时候,执行的数据都是default,否则是没有值
case Todo_UPD:
return state
case Todo_CLEAR:
return {...newState,...{list:[]}}
default :
return state
/*
Error: Reducer "todo" returned undefined during initialization.
If the state passed to the reducer is undefined,
you must explicitly return the initial state. The initial state may not be undefined.
If you don't want to set a value for this reducer, you can use null instead of undefined
这个是初始化 没有返回值
*/
/*
面试题
对象递归
在react数据流,都是要走reducer,当多个功能同时操作state,会出现各种的问题,每次都要做副本的
复制,当一个东西做完之后,另外一个东西,才可以接着做,避免数据的混乱,所以store是只读的
*/
}
}
在store中,combineReducers把多个reducer,合并成一个大的reducer
import { createStore, combineReducers } from 'redux'
// import reducer from './reducers/index.js'
// 分模块后的子reduer
import testReducer from './reducers/text.js'
import todoReducer from './reducers/todo.js'
// let initState={
// // a是跨组件共享的 初始化状态
// a:1
// }
// reducer的作用是用来改变store playload是需要改变的结果 各种电机事件传过来的
// function reducer(state,playload){
// state=initState // 复初始值
// state.a=playload
// }
// combineReducers把多个reducer,合并成一个大的reducer
const reducer=combineReducers({
test:testReducer,
todo:todoReducer
})
// 创建store,主要是共享数据的存储中心 第一个参是必填的,它是reducer
const store = createStore(reducer)
export default store // 根store
/*
1. reducer根据什么变量改成
2. playload是改变的结果,是改成什么样子的
3. reducer根据什么判断把store某个变量改成对应的变量
总结
reducer是用来改变,初始的状态
1.复初始值
2.使用action传来的playload,来修改
高阶函数和组件是用来修饰类
就是纯函数,唯一的输入得到唯一的输出
dispatch 发送一个action到redcer
store的
项目中有多个reducer,reducer合并
1.合并好抛出去
2.把它引入进来在抛出去
combineReducers是合并成一个大的reduer,一些的switch的语句
先合并在使用
1. 定义一个actionTypes,里面多个变量
2. 在每个模块去引入actionTypes,每个模块的case是actionTypes的变量
3. 在统一的出口是,引用createStore, combineReducers,在把多个子模块合并,
const store = createStore(reducer),暴露store
4. 在需要的文件引入把actionType的方法,
使用connect的高阶组件,并且定义2个方法
function mapStateToProps(state){
return {
todolist:state.todo.list
}
}
function mapActionToProps(dispatch){
return{
addTodo:(playload)=>dispatch(addTodo(playload)),
delTodo:(playload)=>dispatch(delTodo(playload)),
updTodo:(playload)=>dispatch(updTodo(playload)),
clearTodo:(playload)=>dispatch(clearTodo(playload)),
}
}
暴露连接的组件
export default connect(mapStateToProps,mapActionToProps )(Todo)
5. 在app.js或main.js,中去引入store
import store from '@/store'
import { Provider } from 'react-redux' 引用上下文
6.
*/
在APP.js中统一,引入 Provider
import React from 'react'
import 'antd/dist/antd.css';
import store from '@/store'
import { QfLayout } from './components'
import { Provider } from 'react-redux'
// 引入路由
import { HashRouter } from 'react-router-dom'
import Login from '@/components/login/login'
// 无状态组件,无状态组件里面是不能使用方法,没有cons
export default class App extends React.Component{
constructor(props){
super(props)
// 初始化的数据,要在constructor中定义
this.state=({
token:localStorage.getItem('token')
})
}
LoginHandle(){
console.log('1212')
}
render(){
let { token }=this.state
return(
<div>
<Provider store={store}>
<HashRouter>
<div className='App'>
{/* onLogin是自定义事件,LoginHandle自定义的方法 */}
{
token
?
<QfLayout></QfLayout>
:<Login onLogin={this.LoginHandle.bind(this)} >
</Login>
}
</div>
</HashRouter>
</Provider>
</div>
)
}
}
// function App(){ 这种是错误的,要把render去掉
// render(){
// return(
//
// App
//
// )
// }
// }
总结:reducer是同步的
action 触发行为,主要的作用是用来触发数据改变的行为
reducer 它的作用就是用来改变store中的数据
store 这是共享数据的存储中心
1、安装
cnpm install redux -S // 创建store
2、定义reducer
// 定义reducer需要两个参数,分别是当前需要被共享的state、用于改变state的action信号
// action={type, payload},type用于指明你想做什么,payload指明你想得到的结果。
function reducer(state={}, action) {
switch(action.type) {
case '1':
// 先深复制,再修改
return state
case '2':
return state
default:
return state
}
}
在实际工作中,reducer要拆分成多个子reducer,也就是多个纯函数。
最终在创建store时,要使用combineReducers进行合并(参见store创建代码)
3、在src/store/index.js创建store并抛出
import { createStore, combineReducers } from 'redux'
// 创建store,必须要传第一个参数是reducer,它是一个纯函数,其作用是用来改变store的
import reducer1 from './reducers/r1'
import reducer2 from './reducers/r2'
const reducer = combineReducers({reducer1, reducer2})
const store = createStore(reducer)
export default store
4、在App.js中进行上下文关联
cnpm install react-redux -S // 把store与react组件关联起来
在App.js中引入store,并使用上下文进行关联
import { Provider } from 'react-redux'
import store from '@/store'
return(
)
5、在页面组件中使用store
import { connect } from 'react-redux'
// 把state中的数据,变成当成组件的props
function mapStateToProps(state){
return {
msg: state.msg
}
}
// 把actions中方法,放在当前组件的props
function mapActionToProps(dispatch) {
return {
changeMsg: ()=>{
// 派发一个action到reducer去
console.log('changeMsg')
}
}
}
export default connect(mapStateToProps,mapActionToProps)(Home)
6、redux异步action
redux默认只支持同步的action。那么异步的action行为(比如调接口)该怎么办呢?
需要使用第三方中间件(redux-thunk),把一步异步的action转化成三个同步的actoin,以此来解决“redux只支持同步action”特点。
这三个同步的action,分别是:第一个action的作用告诉reducer有一个异步行为触发;第二个action告诉reducer异步行为执行成功了,可以更新state了;第三个action是告诉reducer这个异步行为失败了。
7、面试相关
你如何理解redux?flux,地位,三个概念,单向数据流。
store特点:单一数据源、只读、使用纯函数reducer进行修改。
react-redux:Provider connect(mapStateToProps,mapActionToProps)
redux中间件:redux-thunk
dispatch() 发送一个action到reducer
redux
action(vuex的mutation和action的结合)触发行为,主要的作用是用来触发数据改变reducer的行为
reducer 它的作用是改变store中的数据
store共享数据的存储中心
view 数据变化,视图发生变化
在reducer中,使用switch中效率高
在switch中,不能同时使用
return 或break
1.cnpm i redux -S // 创建store
cnpm i react-redux -S // 把store与react组件管理起来
https://react-redux.js.org 这个是react-redux
在全局的App.js 全局引入
状态管理
import { Provider } from ‘react-redux’
import store from ‘@/store’
把所有的东西,都放在 上下文中是把东西注入进来
高阶函数,connect高阶组件(函数)
connect(state,props)(组件名)
纯函数,唯一的输入得到唯一的输出
2.import { createStore } from ‘redux’
3.定义reducer
在store中,2个
创建reducers
index.js
在
在http://cn.redux.js.org/docs/api/createStore.html中,