Flux:Flux 是一种架构思想
https://facebook.github.io/flux/ 官网
资料:
http://www.ruanyifeng.com/blog/2016/01/flux.html
Redux:
Redux 由 Flux 演变而来,但受 Elm 的启发,避开了 Flux 的复杂性。 不管你有没有使用过它们,只需几分钟就能上手 Redux。
Redux 是 JavaScript 状态容器,提供可预测化的状态管理。 (如果你需要一个 WordPress 框架,请查看 Redux Framework。)
可以让你构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。不仅于此,它还提供 超爽的开发体验,比如有一个时间旅行调试器可以编辑后实时预览。
Redux 除了和 React 一起用外,还支持其它界面库。 它体小精悍(只有2kB,包括依赖)。
https://redux.js.org/ 官网
http://www.redux.org.cn/ 中文
资料:
https://segmentfault.com/a/1190000011474522
Vuex:
view <------> store ------------->actions | disptach | 组件 | | view --------->| |commit | | | commit ↓ -------------> mutations -----> state ----> View
Flux:
Flux 的最大特点,就是数据的"单向流动"。
用户访问 View
View 发出用户的 Action
Dispatcher 收到 Action,要求 Store 进行相应的更新
Store 更新后,发出一个"change"事件
View 收到"change"事件后,更新页面
Redux:
安装
npm install --save redux
基本概念:
vuex:store/state/commit/dispatch/getter/module
redux:Action 、Reducer 、Store
1、Store createStore
const store = createStore(reducer);
const {subscribe, dispatch, getState} = store;
getState:获取你所有的state(数据)
dispatch:分发--触发一个动作
subscribe:订阅
2、Reducer 用来做计算 ―― 产生一个新的状态 newState
state + action ==> newState
3、Action 描述 json
格式:
{ type:"动作"添加 删除 。。。 type是固定 payload:"数据" }
Redux:使用步骤
1、先安装
npm i -S redux
2、引入
import {createStore} from "redux"; ES6 const {createStore} require("redux"); ES5
3、写一个计算函数―― reducer
state+action => newState function reducer(state,action){ switch(action.type){ case "xxx" return newState; default: return state; } }
4、创建store
const store = createStore(reducer);
5、操作store下的数据―― state
展现:{store.getState()}
修改:store.dispatch(action);
const {createStore,bindActionCreators,combineReducers} = require("redux");
bindActionCreators:
1、action
2、dispatch
使用格式:
const bindAction = bindActionCreators(fnAction,dispatch);
bindAction();
combineReducers:
//合并reducer 只能有一个reducer
const reducer = combineReducers({ reducer1, reducer2, ...... });
Redux 应用只有一个单一的 store 只有一个单一reducer
exp1:
// import { createStore } from "redux"; const { createStore } = require("redux"); /** * 这是一个 reducer,形式为 (state, action) => newState 的纯函数。 * 描述了 action 如何把 state 转变成下一个 state。 * * state 的形式取决于你,可以是基本类型、数组、对象、 * 甚至是 Immutable.js 生成的数据结构。惟一的要点是 * 当 state 变化时需要返回全新的对象,而不是修改传入的参数。 * * 下面例子使用 `switch` 语句和字符串来做判断,但你可以写帮助类(helper) * 根据不同的约定(如方法映射)来判断,只要适用你的项目即可。 */ function reducer(state = 10, action = {}) { switch (action.type) { case "INCREMENT": return state + 1; case "DECREMENT": return state - 1; default: return state; } } // 创建 Redux store 来存放应用的状态。 // API 是 { subscribe, dispatch, getState }。 let store = createStore(reducer); function log(){ console.log("state:",store.getState()); } // // 可以手动订阅更新,也可以事件绑定到视图层。 store.subscribe(log); // log(); store.dispatch({type:"INCREMENT"}); // log(); store.dispatch({type:"INCREMENT"}); // log(); // 改变内部 state 惟一方法是 dispatch 一个 action。 // action 可以被序列化,用日记记录和储存下来,后期还可以以回放的方式执行
res:
exp2:
//1、引入 const {createStore,bindActionCreators} = require("redux"); //2、创建reducer //state数据初始化 const initState = { count:0 }; const counterReducer = (state = initState,action = {})=>{ //加减 plus/minus 自定义数据 custom switch(action.type){ case "PLUS_ONE": return {count:state.count+1}; case "MINUS_ONE": return {count:state.count-1}; case "CUSTOM_COUNT": return {count:state.count+action.payload.count}; default: return state; } } //3 创建store const store = createStore(counterReducer); store.subscribe(()=> console.log(store.getState())); //action store.dispatch({type:"PLUS_ONE"}); store.dispatch({type:"MINUS_ONE"}); store.dispatch({type:"CUSTOM_COUNT",payload:{count:5}}); //action creaters function plusAction(){ return {type:"PLUS_ONE"}; } function minusAction(){ return {type:"MINUS_ONE"}; } function customCountAction(count){ return {type:"CUSTOM_COUNT",payload:{count}}; } store.dispatch(plusAction()); store.dispatch(minusAction()); store.dispatch(customCountAction(5)); function plusActionWithDispatch(){ const action = {type:"PLUS_ONE"}; store.dispatch(action); } function minusActionWithDispatch(){ const action = {type:"MINUS_ONE"}; store.dispatch(action); } function customCountActionWithDispatch(count){ const action = {type:"CUSTOM_COUNT",payload:{count}}; store.dispatch(action); } plusActionWithDispatch(); minusActionWithDispatch(); customCountActionWithDispatch(5); const bindPlusAction = bindActionCreators(plusAction,store.dispatch); bindPlusAction();
res:
exp3:
<!DOCTYPE html> <html> <head> <title>Redux basic example</title> <script src="./node_modules/redux/dist/redux.js"></script> </head> <body> <div> <p> Clicked: <span id="value">0</span> times <button id="increment">+</button> <button id="decrement">-</button> <button id="incrementIfOdd">Increment if odd</button> <button id="incrementAsync">Increment async</button> </p> </div> <script> function reducer(state = 10, action) { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } } var store = Redux.createStore(reducer) var valueEl = document.getElementById('value') function render() { valueEl.innerHTML = store.getState().toString() } render() store.subscribe(render) document.getElementById('increment') .addEventListener('click', function () { store.dispatch({ type: 'INCREMENT' }) }) document.getElementById('decrement') .addEventListener('click', function () { store.dispatch({ type: 'DECREMENT' }) }) document.getElementById('incrementIfOdd') .addEventListener('click', function () { if (store.getState() % 2 !== 0) { store.dispatch({ type: 'INCREMENT' }) } }) document.getElementById('incrementAsync') .addEventListener('click', function () { setTimeout(function () { store.dispatch({ type: 'INCREMENT' }) }, 1000) }) </script> </body> </html>
res:
exp4:
//1、引入 const {createStore,combineReducers} = require("redux"); //2、创建reducer //state数据初始化 const initState = { count:0 }; const counterReducer = (state = initState,action = {})=>{ //加减 plus/minus 自定义数据 custom switch(action.type){ case "PLUS_ONE": return {count:state.count+1}; case "MINUS_ONE": return {count:state.count-1}; case "CUSTOM_COUNT": return {count:state.count+action.payload.count}; default: return state; } } const myReducer = (state = [],action={}) => state; //合并reducer 只能有一个reducer const reducer = combineReducers({ counterReducer, myReducer, }); //3 创建store //const store = createStore(counterReducer); const store = createStore(reducer); console.log("state:",store.getState());
res:
--------------------------------------
Object.assign(target目标,数据源多个);
作用:
1、拷贝 ―― 浅拷贝
2、合并对象―― 后面的属性会覆盖前面的属性
3、继承
和jquery extend一样
$.extend默认是浅拷贝 如果要实现深度拷贝
$.extend(true,target目标,数据源多个);
自己实现一个深度拷贝
JSON.parse/stringify
exp1:
复制,合并
<script> //Object.assign $.extend var a = {a:"a"}; var b = {b:"b"} var x = Object.assign({},a,b); console.log(x==a,x,a,b); </script>
res:
exp2:
//属性重复 后面的属性会覆盖前面的属性
<script> //Object.assign $.extend //属性重复 后面的属性会覆盖前面的属性 var a = {a:"a"}; var b = {a:"b",b:"b"}; var c = {a:"c",b:"c",c:"c"} var x = Object.assign({},a,b,c); console.log(x,a,b,c); </script>
res:
exp3:
//Object.assign是一个浅拷贝
浅拷贝指的是拷贝后的元素变化会影响的原来的元素; 只拷贝了地址
<script> //Object.assign $.extend //深拷贝 浅拷贝 //属性重复 后面的属性会覆盖前面的属性 //Object.assign是一个浅拷贝 var a = {a:1,b:2,arr:[1,2]}; var b = {} Object.assign(b,a); b.arr[0] = "bbb"; console.log(a,b,a==b); </script>
res:
exp4:
深拷贝
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script> //Object.assign === $.extend//浅拷贝 默认是浅拷贝 //深拷贝 浅拷贝 //属性重复 后面的属性会覆盖前面的属性 //true表示深拷贝 var a = {a:1,b:2,arr:[1,2]}; var b = {}; $.extend(true,b,a); b.arr[0] = "bbb"; console.log(a,b,a==b); </script>
res:
exp5:
<script> //copy JSON.parse/stringify var a = {a:1,b:2,arr:[1,2]}; var b = copy(a); b.arr[0] = "bbb"; function copy(obj){ //转成字符串,再转成json,地址变了, return JSON.parse(JSON.stringify(obj)); } console.log(a,b,a==b); </script>
res:
exp6:
<script> function Person(name,age){ this.name = name; this.age = age; } Person.prototype.getName = function(){ return this.name; } function Worker(name,age,job){ //Person.call(this,name,age); Object.assign(this,{name,age,job}); } //Worker.prototype = new Person(); Object.assign(Worker,Person); Worker.prototype.getJob = function(){ return this.job; } console.log(Worker.prototype,Person.prototype); </script>
res:
exp7:
react状态
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Page Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="react.js"></script> <script src="react-dom.js"></script> <script src="babel.js"></script> <script type="text/babel"> //状态 class Test extends React.Component{ constructor(...args){ super(...args); this.state = { a:1,b:2, count:0 } } plus(){ let oldSate = this.state; let obj = { count:this.state.count+1 }; this.setState(obj); setTimeout(()=>{ console.log(1,this.state == obj,this.state,obj); },0); } render(){ return <div> count:{this.state.count} <input onClick={this.plus.bind(this)} type="button" value="按钮"/> </div> } } ReactDOM.render( <Test/>, document.getElementById("app") ); </script> <body> <div id="app"></div> </body> </html>
res:
exp8:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Page Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="react.js"></script> <script src="react-dom.js"></script> <script src="babel.js"></script> <script type="text/babel"> //状态 let state = {a:1,b:2,count:1,msg:""}; function setState(newState){ //复制,形同的取后面的 //state = Object.assign({},state,newState); //结构去重 state = {...state,...newState}; renderApp(); } class Test extends React.Component{ plus(){ let oldState = state; setState({ count:state.count+1 }); console.log(state == oldState,state); } show(ev){ setState({ msg:ev.target.value }); } render(){ console.log("渲染了",state); return <div> count:{state.count} <input onClick={this.plus.bind(this)} type="button" value="按钮"/> <br /> <input onChange={this.show.bind(this)} type="text" value={state.msg}/> {state.msg} </div> } } renderApp(); //把渲染封装成函数 function renderApp(){ ReactDOM.render( <Test/>, document.getElementById("app") ); } </script> <body> <div id="app"></div> </body> </html>
res:
==不用react-redux==:
页面渲染:
1.this.setState({})
此函数自动渲染页面.
2.给将render封装成函数,改变数据需要更新页面时调用,
3.index.js中的React.render(),封装成函数,添加store.subscribe(函数名)监听,适合页面较多的情况.
==react-redux: 帮你渲染页面==
cnpm i -S react-redux
import {Provider,Connect} from "react-redux";
index.js:
import React from 'react'; import ReactDOM from 'react-dom'; import {Provider} from "react-redux"; import store from "./react-redux/store"; import App from './react-redux/Counter'; import registerServiceWorker from './registerServiceWorker'; ReactDOM.render( //组件Provider,引入store. <Provider store={store}> <App /> </Provider>, document.getElementById('root')); registerServiceWorker();
Counter.js:
高阶组件HOC
import React,{Component} from "react"; import {connect} from "react-redux"; class Counter extends Component{ constructor(...args){ super(...args); console.log("counet props",this.props); } render(){ console.log("渲染了"); const {count,dispatch} = this.props; return <div> <input onClick={()=>dispatch({type:"MINUS_ONE"})} type ="button" value="-"/> <span>{count}</span> <input onClick={()=> dispatch({type:"PLUS_ONE"})} type="button" value="+"/> </div> } } //高阶组件HOC /* export default connect(function(state){ console.log(111,state); return state; })(Counter); */ //export default connect(state=>({count:state.count}))(Counter); /* function mapStateToPros(state){ return { count:state.count } } export default connect(mapStateToPros)(Counter); */ const mapStateToPros = state =>({count:state.count}); export default connect(mapStateToPros)(Counter);
高阶组件:只负责数据 不涉及UI
exp1:
<script type="text/babel"> class Clock extends React.Component{ state = {time:new Date()}; timer = null; componentDidMount(){ this.tick(); } componentWillUnmount(){ clearInterval(this.timer); } tick(){ this.timer = setInterval(()=>{ this.setState({ time:new Date() }); },1000); } render(){ return <div> <div> time:{this.state.time.toLocaleTimeString()} </div> </div> } } ReactDOM.render( <Clock/>, document.getElementById("app") ); </script>
res:
exp2:
<script type="text/babel"> /* function connect(fn){ //fn... return function(WrappedComponent){ return class extends React.Component { render(){ return null; } } } } connect(fn)(WrappedComponent) */ //高阶组件 1是一个函数 2 返回一个新组件 function withTime(WrappedComponent) { return class extends React.Component { state = {time:new Date()}; timer = null; componentDidMount(){ this.tick(); } componentWillUnmount(){ clearInterval(this.timer); } tick(){ this.timer = setInterval(()=>{ this.setState({ time:new Date() }); },1000); } render() { return <WrappedComponent time={this.state.time} />; } }; } class Clock0 extends React.Component{ render(){ return <div> <div> Clock1:{this.props.time.toString()} </div> </div> } } class Clock1 extends React.Component{ render(){ return <div> <div> Clock1:{this.props.time.toString()} </div> </div> } } class Clock2 extends React.Component{ render(){ return <div> <div> Clock2:{this.props.time.toLocaleString()} </div> </div> } } Clock1 = withTime(Clock1); Clock2 = withTime(Clock2); ReactDOM.render( <div> <Clock0 time={new Date()}/> <Clock1/> <Clock2/> </div>, document.getElementById("app") ); </script>
res:
来源:https://www.cnblogs.com/zhongchao666/p/9471290.html