07/redux
<pre> 当有如下需要可以考虑使用redux: 当组件的状态,需要共享 某个状态需要在任何地方都可以拿到 一个组件需要改变全局状态 一个组件需要改变另一个组件的状态 vue中是 store(state,mutation,action) |----------------------- | | action --->mutation | |-- ↑------- ↑ | dispatch | | | | | | | | | ↓ | component<-----|-----state | |-------------- | state可以由组件直接获取得到 组件diapatch action 或commit mutation 来实现数据state的修改 react没有vuex那么清晰,在store里定义state(状态),action等 主要定义reducer和action react中reduce相当于mutation,store不需要定义声明,有reducer自动完成 组件通过store.getState()获得状态 组件怎么改状态?通过容器dispatch去改-->也就是store.dispatch(Action) 这个Action相当于重新触发掉了reducer 重新产生State,State一变化就触发组件变化。流向和vuex是一样的 component--->Action--->reducer--->state--->component 但是不把store,reducer,action全部叫store 这每一个东西都是普通的 </pre>
02
<script type="text/babel"> //count数据 用redux存 //VUEX的使用:1)创建容器 定义state,action,mutation 2)容器挂载到Vue实例上 3)组件获取状态或修改状态 //Redux: //reducer:用于产生state的函数 定义reducer才能知道count是什么数据 // reducer根据对应的action产生state //action 是个普通对象,用于记录用户的行为 里面属性其实可以随便定,但规范上一般是给{type:''} // store 根据reducer函数创建 //六步骤 //1.定义Reducer:是个函数 怎么定义随意 名字随便取,但是里面参数的含义是固定的 //第一个参数,上一次的状态 state是由reducer创建的,所以一次都没调用的时候可能没有定义,可以给个初始化 //第二个参数是用户提交的action对象 //返回值为新状态 function myCount(state=0,action){ //这个state其实就代表count //reducer就是根据action产生state //传递给我的action到底是个什么行为,所有要根据action.type判断 //reducer最终返回的是一个新状态 switch(action.type){ case 'ADD': return state+1 case 'SUB': return state-1 //一定要定义默认情况 default:return state //返回旧状态 } } //2.reduce做好后创建容器 // 创建store:用Redux.createStore 这个方法接受一个参数,就收Reducer作参数 根据这个Reducer就能产生容器(store) const store=Redux.createStore(myCount) //3.有时候可写可不写,简单的话可以不写 创建Action函数,Action Creator 是个函数,作用是创建action(一个对象) return一个对象 //可以由参数也可以没有 function setCount(type){ //返回Action return{ type } } //4 创建组件 获取状态 修改状态 class App extends React.Component{ add=()=>{ //让状态+1 reducer已将帮你做了 只要去执行一遍就行 //只要去调用reducer 这时候用store.dispatch store是全局变量 //dispatch参数为action //addCount就是帮我们生成action对象的 所以这里得dispatch的参数就位action函数 否则简单的话可以不用这个addCount函数 直接store.dispatch({type:"ADD"}) store.dispatch(setCount('ADD')) //一dispatch 马上就会去调用reducer函数(也就是myCount),action传给myCount的第二个参数 这时候state就变了 state+1了 //但这时候是不会更新视图的 } sub=()=>{ //让状态-1 store.dispatch(setCount('SUB')) } render(){ return( <div> {/*获取状态 store.getState() 拿到了state(就是count数字)*/} <p>{store.getState()}</p> <button onClick={this.add}>+</button> <button onClick={this.sub}>-</button> </div> ) } } //5.渲染组件 ReactDOM.render(<App/>,document.getElementById('root')) //6.监听状态变化,重新渲染页面 store.subscribe会自动监听state的更新 store.subscribe(function(){ ReactDOM.render(<App/>,document.getElementById('root')) }) </script>
03
<div id='root'></div> <script src="./react.js"></script> <script src="./react-dom.js"></script> <script src="./react-router-dom.js"></script> <script src="./redux.js"></script> <script src="./babel.min.js"></script> <script type="text/babel"> //需求:共享数据count,行为有:加某个值,减某个值 //1.定义Reducer:Reducer是函数,用于根据就状态和Action产生新状态 //myCount这个函数由你去定义但不是不是由你直接去调用 而是由你去dispatch的时候由内部的Redux通过store自动的去调用 //所以里面的形参不能换顺序,调用者根据规则去调用的,所以要按规则去定义,第一个就要定义state,第二个是action //redux的action个vuex不同 vuex的action是方法(函数), redux的是对象 且有不成文的规则,要有一个type属性 不叫type也可以 不过都用type {type} //state=0这个初始值可以在创建recuder的时候在形参里设置,也可以在第二步创建容器的时候指定 function myCount(state=0,action){ debugger switch (action.type) { //action:{type:表示行为名称,payload:行为所携带的数据(推荐用payload)} case 'ADD': return state+action.payload case 'SUB': return default: return state-action.payload } } //2.创建容器 第一个参数就是recuder,第二个参数就是状态初始值(可选,但这里不写那么reducer(myCount)就要写,否则会显示NAN) const store = Redux.createStore(myCount,0) //3.定义创建Action的方法,Action Creator function myActionCreator(type,payload=1) { return { type, payload } } //4.设计组件 class App extends React.Component{ render(){ console.log(store.getState()) debugger return( <div> <p>{store.getState()}</p> <button>+</button> <button>-</button> </div> ) } } function myRender(){ ReactDOM.render(<App/>,document.getElementById('root')) } myRender() //这里只是讲的redux redux本身是不能自动更新组件的(state变化的话) 后面有一个react-redux 这个做的是自动监听state变化 会直接引起视图变化 只用redux才有第五步 //5.监听状态改变 store.subscribe(myCount)是有返回值的 执行这个返回值就会解除监听 var unSubScribe=store.subscribe(myCount) // setTimeout(()=>unSubScribe(),20000)//解除监听 </script>
04
<style> .del{ text-decoration: line-through } </style> </head> <body> <div id='root'></div> <script src="./react.js"></script> <script src="./react-dom.js"></script> <script src="./react-router-dom.js"></script> <script src="./redux.js"></script> <script src="./babel.min.js"></script> <script type="text/babel"> //1.设置reducer function todoList(state=[],action){ switch (action.type) { case 'ADD_LIST': return [ ...state, action.payload ] case 'DELETE_ITEM': return [ ...state.slice(0,action.index), ...state.slice(action.index+1) ] case 'TOGO_TODO': return [ ...state.slice(0,action.index), Object.assign(state[action.index],{isCompleted:!state[action.index].isCompleted}), ...state.slice(action.index+1) ] case 'CLEAR_LIST': return [] default: return state } } //多个reducer可以合并 const totalCount=function(state=0,action){ switch(action.type) { case 'CHANGE_TOTAL': //修改总数量 return action.payload case 'ADD_TOTAL': return state+1 case 'SUB_TOTAL': return state-1 default: return state } } //combineReducers的参数,为一个对象,该对象key是state中的属性,value是产生对应state的reducer函数 const allReducer=Redux.combineReducers({ todoList, totalCount }) //2.创建容器 const store=Redux.createStore(allReducer) //3.设置action Creator function addlist(payload){ return { type:'ADD_LIST', payload } } function deleteItem(index){ return { type:'DELETE_ITEM', index } } function check(index){ return { type:'TOGO_TODO', index } } //定义totalChange的Action Creator function changeTotalCount(){ return } //4 创建UI class App extends React.Component{ render(){ return(<div> 标签内容 <TodoList/> <AddItem/> </div>) } } class TodoList extends React.Component{ del=(index)=>{ store.dispatch(deleteItem(index)) } check=(index)=>{ store.dispatch(check(index)) } render(){ return(<ul> {store.getState().todoList.map((val,index)=>{ return(<li> <input type="checkbox" checked={val.isCompleted} onChange={e=>this.check(index)} /> <span className={val.isCompleted?'del':''}>{val.content}</span> <button onClick={e=>this.del(index)}>删除</button> </li>) }) } </ul>) } } class AddItem extends React.Component{ add=()=>{ this.inputItem.value!==''?store.dispatch(addlist({content:this.inputItem.value,isCompleted:false})):alert('请输入事件') } render(){ return(<div> <input ref={(el)=>this.inputItem=el}/> <button onClick={this.add}>保存</button> </div>) } } function render(){ ReactDOM.render(<App/>,document.getElementById('root')) } render() store.subscribe(render) </script>
05
<div id='root'></div> <script src="./react.js"></script> <script src="./react-dom.js"></script> <script src="./react-router-dom.js"></script> <script src="./redux.js"></script> <script src="./babel.min.js"></script> <script type="text/babel"> class App extends React.Component{ constructor(props){ super(props) } add=()=>{ //让状态+1 reducer已将帮你做了 只要去执行一遍就行 //只要去调用reducer 这时候用store.dispatch store是全局变量 //dispatch参数为action //addCount就是帮我们生成action对象的 所以这里得dispatch的参数就位action函数 否则简单的话可以不用这个addCount函数 直接store.dispatch({type:"ADD"}) // store.dispatch(setCount('ADD')) //一dispatch 马上就会去调用reducer函数(也就是myCount),action传给myCount的第二个参数 这时候state就变了 state+1了 //但这时候是不会更新视图的 } sub=()=>{ //让状态-1 store.dispatch(setCount('SUB')) } render(){ return( <div> </div> ) } } const a1=new App() debugger //5.渲染组件 ReactDOM.render(<App/>,document.getElementById('root')) //6.监听状态变化,重新渲染页面 store.subscribe会自动监听state的更新 store.subscribe(function(){ ReactDOM.render(<App/>,document.getElementById('root')) }) </script>
06
<div id='root'></div> <script src="./react.js"></script> <script src="./react-dom.js"></script> <script src="./react-router-dom.js"></script> <script src="./redux.js"></script> <script src="./babel.min.js"></script> <script type="text/babel"> //1.定义reducer 是个函数 function reducer1(state = 0 ,action){ switch (action.type){ default:return state ;break; } } //2.reducer做好后创建容器 const store = Redux.createStore(reducer1) //3.创建action函数,作用是return一个对象 function action(type){ return type } //创个组件 class App extends React.Component{ render(){ return <div>11</div> } } ReactDOM.render(<App/>,document.getElementById('root')) </script>