什么是Redux?

263 阅读3分钟

追求知识本质,不进行知识二次加工。

1、纯函数

pure function 是一种函数,有几个特性:

  • 相同输入得到相同输出
  • 没有副作用 side effects
  • 不依赖于外部状态

比如这个就是一个纯函数:

function add(a, b){
	return a + b;
}

比如下面就不是一个纯函数:

// 不满足第一条
function add(a, b){
	return a + b + Math.random();
}
// 不满足第二条
function add(a, b){
    fetch('/api/getlist')
    return a + b;
}
// 不满足第三条
var o = 3;
function add(a, b){
    return a + b + o;
}
// 不满足第三条
function add(a, b){
    a++
    return a + b;
}

再用数组的操作举例:

// slice是纯函数  splice不是纯函数
var xs = [1,2,3,4,5];

// 纯的
xs.slice(0,3);
//=> [1,2,3]

xs.splice(0,3);
//=> [4,5]

2、函数式编程

JS中函数是一等公民,可以当做参数传递给另一个函数。 函数式编程(FP,functional programming),主要有几个特点:

    1. 函数是”一等公民”
    1. 只用”表达式",不用"语句"
    1. 没有”副作用"
    1. 不修改状态
    1. 引用透明(函数运行只靠参数)

函数式编程的好处:

  • 代码简洁,开发快速,代码耦合性低
  • 接近自然语言,易于理解
  • 不依赖状态,方便管理代码
  • 易于"并发编程",因为不修改变量,没有"锁"
  • 代码热升级。因为没有副作用,相同输入得到相同输出

3、redux简版

比如有个需求,有对象obj,有个属性todos,实现一个功能,让todos进行增加和减少

var obj = {
    todos: 0
}
// 根据type觉得进行增加或者减少
var type = 'ADD'

if (type === 'ADD') {
    obj.todos++
} else if (type === 'MINUS') {
    obj.todos--
}
console.log(obj.todos) // 1

我们将改变的代码封装成函数:

var obj = {
    todos: 0
}

// * 这个函数接收两个参数obj和type,此时type决定了obj如何更改。
// * 这个函数不是纯函数,因为它直接改变了传入的参数obj的值。
function change(obj, type) {
    if (type === 'ADD') {
        obj.todos++
    } else if (type === 'MINUS') {
        obj.todos--
    }
}

change(obj,'ADD')
console.log(obj.todos) // 1

我们现在用纯函数来改变一下

var obj = {
    todos: 0
}

function change(obj, type) {
    if (type === 'ADD') {
        return {
            ...obj,
            todos: obj.todos + 1
        }
        
    } else if (type === 'MINUS') {
        return {
            ...obj,
            todos: obj.todos - 1
        }
    }
}

var obj2 = change(obj,'ADD')
console.log(obj1.todos) // 0 不变
console.log(obj2.todos) // 1

现在想增加一些业务,比如,现在希望change函数能够自由的控制每次加多少、减多少

var obj = {
    todos: 0
}

function change(obj, action) {
    if (action.type === 'ADD') {
        return {
            ...obj,
            todos: obj.todos + action.todo
        }
        
    } else if (action.type === 'MINUS') {
        return {
            ...obj,
            todos: obj.todos - + action.todo
        }
    }
}

var obj2 = change(obj,{type:'ADD', todo: 10})
console.log(obj1.todos) // 0 不变
console.log(obj2.todos) // 10

上面这个函数非常的有意思,它接收两个参数obj、action,根据action返回一个新的对象,这个对象是从obj“变化”来的。

  • 这个change函数我们术语叫做reducer。reducer的英语意思是反应容器。

我们继续抽象。现在我们抽象出一个store,store是Store类的实例,在构建的时候,需要传入reducer。

function Store(reducer) {
        // 自己的reducer
	this.reducer = reducer;
	// 数据,就需要调用一个次reducer,才能得到这个对象
	// 因为数据的默认值,是写在reducer里面的形参的默认值的位置上
	this.state = this.reducer(undefined,{});
}

Store.proptytope.getState = function(){
    return {
        ...this.state
    }
}

Store.proptytope.dispatch = function(action){
   this.state = this.reducer(this.state, action);
}


function reducer(state= {"todos" : 0}, action) {
    if (action.type === 'ADD') {
        return {
            ...state,
            todos: state.todos + action.todo
        }
        
    } else if (action.type === 'MINUS') {
        return {
            ...state,
            todos: state.todos - + action.todo
        }
    }
    return state
}


// 实例化一个store,不new等于白写。
var store = new Store(reducer);

// 得到值,调用getState()函数,得到里面的todos值
console.log(store.getState().todos);			//0


// 唯一能够改变state的方法就是发出dispatch,不发出dispatch不能改变state的值
store.dispatch({"type":"ADD","todo":1});	
store.dispatch({"type":"ADD","todo":1});	
store.dispatch({"type":"ADD","todo":1});	

// 得到值
console.log(store.getState().todos);			//3

函数式编程自己没啥用,但是在函数是编程的要求下,就能够有好多工具产生了,比如“可预测状态容器”(predictable state container)。我们刚才写的案例就是可预测状态容器。也就是简版的redux

  • 这就是函数式编程的函数,数据、值、变化相互没有关系,是不耦合的,需要有关系的时候,才让他们产生关系,比如下面的语句。
var store = new Store(reducer);

总结

  • 1、纯函数的判断方式
  • 2、函数式编程的好处
  • 3、redux的发展由来