24.redux
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:
24.redux的更多相关文章
- 如何使用24行JavaScript代码实现Redux
作者:Yazeed Bzadough 译者:小维FE 原文:freecodecamp 为了保证文章的可读性,本文采用意译而非直译. 90%的规约,10%的库. Redux是迄今为止创建的最重要的Jav ...
- react+redux教程(三)reduce()、filter()、map()、some()、every()、...展开属性
reduce().filter().map().some().every()....展开属性 这些概念属于es5.es6中的语法,跟react+redux并没有什么联系,我们直接在https:// ...
- [React Testing] The Redux Store - Multiple Actions
When using Redux, we can test that our application state changes are working by testing that dispatc ...
- Redux管理你的React应用
使用Redux管理你的React应用 因为redux和react的版本更新的比较频繁,博客园这里用的redux版本是1.0.1,如果你关心最新版本的使用技巧,欢迎来我的Github查看(https ...
- redux 最简例子
方便初学redux的同学学习,这里是最简单的redux例子 1 import React, {Component, PropTypes} from 'react' 2 import ReactDOM ...
- [React] react+redux+router+webpack+antd环境搭建一版
好久之前搭建的一个react执行环境,受历史影响是webpack3.10.0和webpack-dev-server2.7.1的环境,新项目准备用webpack4重新弄弄了,旧的记录就合并发布了(在没有 ...
- 教你如何在React及Redux项目中进行服务端渲染
服务端渲染(SSR: Server Side Rendering)在React项目中有着广泛的应用场景 基于React虚拟DOM的特性,在浏览器端和服务端我们可以实现同构(可以使用同一份代码来实现多端 ...
- 前端(十):使用redux管理数据
react本身能够完成动态数据的监听和更新,如果不是必要可以不适用redux. 安装redux: cnpm install redux --save,或者yarn add redux. 一.react ...
- [翻译]Review——24 tips for React Native you probably want to know
Post author: Albert Gao Post link: http://www.albertgao.xyz/2018/05/30/24-tips-for-react-native-you- ...
随机推荐
- 用原生javascript写出jquery中slideUp和slideDown效果
设置块级元素的CSS属性overflow为hidden,然后动态改变height即可 var header=document.getElementsByTagName('header')[0]; he ...
- 通过Pdf预览Excel或者word或者Powerpoint (C#将Office转换为PDF)
下面代码是Excel转换为PDF using System; using System.Collections.Generic; using System.Linq; using System.Web ...
- IIS安装、配置 发布网站 报错解决方案
错误一: HTTP 错误 500.19- Internal Server Error法请求该页面配置,因为页面的相关配置数据无效#### HTTP 错误 500.21 - Internal S ...
- CMD批处理循环,太强大了(转)
终极dos批处理循环命令详解格式:FOR [参数] %%变量名 IN (相关文件或命令) DO 执行的命令 作用:对一个或一组文件,字符串或命令结果中的每一个对象执行特定命令,达到我们想要的结果. ...
- MultipartFile文件编码判断
MultipartFile文件编码判断 搜索:Java 判断文件的字符集编码 https://blog.csdn.net/top_code/article/details/8891796 但是在Mul ...
- 在Centos7下安装nghttp2
如果是Ubuntu18.04, 系统本身已经带了nghttp2了, 直接apt安装就可以. 下载源代码 https://github.com/nghttp2/nghttp2 如果是在Ubuntu下编译 ...
- WINDOWS API ——GETFILETIME——获取文件时间
GetSystemTime(LPSYSTEMTIME lpSystemTime)得到系统时间,这个时间是标准的UTC时间,也就是没有包含任何时区的时间的GetLocalTime(LPSYSTEMTIM ...
- springboot配置idea 热部署
背景: 在开发中,当我们修改代码之后,每次都要重新启动,很是浪费时间,在springboot中就有一种热部署方式,可以实现想要修改不需要每次都重新启动,保存即可生效 用法: 一.maven 添加 ...
- SNF软件开发机器人-子系统-功能-【列表】自由排序-如何配置?
[列表]自由排序 1.效果展示: 2.使用说明: 打开显示页面,点击开发者选项的简单配置按钮.在功能表信息中选择自由排序复选框后保存.
- 在新安装的Centos中安装python3.7 解决pip和yum问题
首先要先安装依赖包: yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-deve ...