react-redux初探

前言

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。

所以redux是容器。容器是什么呢?杯子,箱子,罐子等等都是容器;这是的容器是指web容器,web容器是应用服务器中位于组件和平台之间的接口集合。所以redux是接口的集合。redux有哪些接口呢? 比如 redux.createStore()
谨记redux是容器。

redux流程图

流程图可以在理解之后,再看。可能表达的不准确。不过应该差不多。

结合html代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<script type="text/javascript">
// 这个是一个reducer,形式(state,action)=> state 的纯函数。
// 纯函数,不改变传入的参数
// 这个是一个反应釜,描述了action如何把state转变成下一个state的。
// reducer中的state只能通过action改变。
const reducer = (state = {"v":10},action)=>{
if( action.type == "ADD"){
return {"v":state.v + 1}
}else if( action.type == "MINUS"){
return {"v":state.v - 1}
}
return state;
}
// 创建 Redux store来存放应用的状态
// store我们翻译过来是“仓库”,这个是一个存放数据并且可以操作数据的东西。
const store = Redux.createStore(reducer);
// 书写一个视图函数
const render = ()=>{
document.getElementById("title").innerHTML = store.getState().v
}
// 调用一下render的函数
render();
// 现在要将stroe注册到视图,这样的话,当stroe中的数据发生变化的时候,就能自动的调用render函数了。
// subscribe 订阅
store.subscribe(render);
// 事件监听
document.getElementById("btn1").onclick = function(){
// dispatch 是派遣,调度 ,这里要 dispatch 一个action
// 所谓的action就是一个JSON,里面一定有type属性,表示要做的动作。
store.dispatch({"type":"ADD"})
}
document.getElementById("btn2").onclick = function(){
// dispatch 是派遣,调度 ,这里要 dispatch 一个action
// 所谓的action就是一个JSON,里面一定有type属性,表示要做的动作。
store.dispatch({"type":"MINUS"})
}
</script>

为什么使用redux

因为在开发react的时候,有俩个痛点:

  • 组件嵌套层级深,回调地狱。你可能会在一个较深层次的组件里需要更新全局state的某个字段,却无奈只能通过从顶层组件一层一层传递下来的props进行回调(也就是 子组件通信问题).

  • 页面的state不可预测。由于state缺乏一种可预测的机制,导致用户在进行一些页面操作(更改state),或者异步请求有新的数据从服务端返回的时候,state的变化已经不可控制,很容易产生bug(跨页面数据共享问题,如多页面购物车数据).

    redux是怎么解决React痛点的?

  • 1、通过react-redux提供的Provider组件,在根组件外面包一层,这样根组件,以及所有的子组件都能拿到store。实现的原理是基于React自身提供的context属性,但是react官方不推荐直接在组件中使用this.context。所以react-redux提供了另一种方法connect,通过connect将普通的UI组件升级为容器组件,同时将获取store的细节也一并封装在生成容器组件的代码中,从而容器组件可以直接拿到store

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <Provider store={store}>
    <App/>
    </Provider>

    // 定义App组件
    class Foo extends React.Component{
    render() {
    const { text } = this.props;
    return <div>{text}</div>;
    }
    }
    const App = connect(
    mapStateToProps,
    mapDispatchToProps
    )(Foo);
  • 2、使用纯函数修改state,保证state变化可预测。每次更改都返回一个全新的state。

  • 3、遵守容器组件与展示组件分离的原则。这是redux一个重要的思想,容器组件和展示组件各司其职。

    immutable.js

    immutable.js 来自facebook,它是官方推荐的库。
    immutable.js 提供了大量的“纯函数”。
    immutable 三步走:

  • 1、先用fromJS()或list()或map()将原生的JS的数组、对象变为list、map对象。

  • 2、然后进行push,pop等操作。

  • 3、然后toJS()变成原生的数组、对象。

    1
    2
    3
    4
    5
    6
    7
    8

    var immutable = require("immutable");
    var List = immutable.List;

    const list1 = List(["飞机","货车","火车","轮船","马车"]);
    const list2 = list1.push("卡车");
    console.log(list1.toJS());
    console.log(list2.toJS());

    为什么使用immutable.js

    首先,在没有immutable.js的情况下,碰到较深层次的数据结构时,更新state会变得很麻烦。
    旧的state:

    1
    2
    3
    4
    5
    6
    7
    8
    {
    priceInfo: {
    price: 200,
    promotion: {
    offValue: 30
    }
    }
    }

现在需要只更新offValue的值为50,该怎么处理呢?

1
2
3
let newState = _.cloneDeep(this.state);
newState.priceInfo.promotion.offValue = 50;
this.setState(newState);

可以看到,需要先深度复制一份this.state,然后修改offValue的值,最后执行setState。除了这个过程的有点复杂,另外深度复制对象是挺耗性能的一件事。而通过Immutable.js,我们只需要这样做:

1
2
3
4
5
6
7
8
9
let initialState = Immutable.fromJS({
priceInfo: {
price: 200,
promotion: {
offValue: 30
}
}
});
this.setState(initialState.setIn(['priceInfo', 'promotion', 'offValue']), 50);

参考

Redux 入门教程(一):基本用法

redux常见问题答疑