4. Redux是啥?

我们用「原生JS + Redux」来完成一个「Counter」的小需求。

在上一节中(https://www.jianshu.com/p/ff0bfe9a0981),我们已经用过「Redux」改写过需求。今天我们再来剖析下「Redux」。

JS代码:

let createStore = Redux.createStore;

let store = createStore(stateChanger);


// stateChanger函数里面,集合了所有「数据修改」操作
function stateChanger(state, action) {
  if(typeof state === "undefined") {
    state = 0;
  }
  switch(action.type) {
    case 'ADD':
      return state = state + action.payload;
    case 'MINUS':
      return state = state - action.payload;
    default:
      return state;
  }
}


function render() {
  let app = document.querySelector('#root');
  app.innerHTML = `
    
${store.getState()}
`; } function add() { // dispatch相当于发送一个action,然后根据「stateChanger」 // 里面的类型,进行数据更新 store.dispatch({type: 'ADD', payload: 1}); } function minus() { store.dispatch({type: 'MINUS', payload: 1}); } function addOdd() { if(store.getState() % 2 === 1) { store.dispatch({type: 'ADD', payload: 2}); } } function addAsync() { setTimeout(() => { store.dispatch({type: 'ADD', payload: 2}); }, 1000) } render(); // 监听store,如果store发生变化,则执行回调函数。 store.subscribe(() => { render(); });

总结下上述代码,「Redux」会多几个术语,分别为「store,stateChanger,dispatch,subscriber」。

  • store,顾名思义,就是所有数据的集合。
  • stateChanger,一般也称为「reducer」,就是所有「更新数据的行为」的集合。
  • dispatch,可以理解为发送action,然后根据「stateChanger」里面的action type来更新「store」里面的数据。
  • payload, 就是action里面的data值。
  • subscriber,监听「store」,一旦「store」里面的数据有变动,就会执行回调函数,一般这个回调函数就是render函数,来重新渲染需要更新的页面。

接下来我们进入「第二阶段」,运用「React」和「Redux」来再次实现上述需求。

我们需要装一个包「create-react-app」,可以为我们搭建好一个React环境。同时记得装「Redux」。都安装好后,项目结构如下:


4. Redux是啥?_第1张图片
image.png

我们只操作「App.js」和「index.js」文件。

App.js

import React, { Component } from 'react';

class App extends Component {

  add() {
    this.props.store.dispatch({type: 'ADD', payload: 1});
  }

  minus() {
    this.props.store.dispatch({type: 'MINUS', payload: 1});
  }

  addOdd() {
    if(this.props.store.getState() % 2 === 1) {
      this.props.store.dispatch({type: 'ADD', payload: 2});
    }
  }

  addAsync() {
    setTimeout(() => {
      this.props.store.dispatch({type: 'ADD', payload: 1});
    }, 1000);
  }

  render() {
    return (
      
{this.props.store.getState()}
); } } export default App;

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {createStore} from 'redux';

let store = createStore(stateChanger);

function stateChanger(state, action) {
    if(typeof state === "undefined") {
        state = 0;
    }
    switch(action.type) {
        case 'ADD':
            return  state = state + action.payload;
        case 'MINUS':
            return  state = state - action.payload;
        default:
            return state;
    }
}


render();

store.subscribe(() => {
    render();
})

function render() {
    ReactDOM.render(, document.getElementById('root'));

}

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();

我们换了「React+Redux」方案后,可以打开「开发者工具」,看到最显著的变化就是,这样只会局部更新。更新需要改变的节点。

但是也产生一个问题的子组件中,如果要用类似「store」的属性,必须一层层传下去,然后通过「props」获取,像「传家宝」一样。。。那有没有什么办法,使得每层直接获取「store」不用每层传递呢?

我们进入第三阶段,引用「React-Redux」。同样只是修改「App.js」和「index.js」。

App.js

import React, { Component } from 'react';

import { connect } from 'react-redux';


class App extends Component {


  addOdd() {
    if(this.props.number % 2 === 1) {
      this.props.addOdd()
    }
  }

  addAsync() {
    setTimeout(() => {
      this.props.addAsync();
    }, 1000)
  }

  render() {
    return (
      
{this.props.number}
); } } const mapStateToProps = (state) => { return { number: state.number } }; // 注意「mapDispatchToProps」是一个对象 const mapDispatchToProps = { add: () => { return { type: 'ADD', payload: 1 } }, minus: () => { return { type: 'MINUS', payload: 1 } }, addOdd: () => { return { type: 'ADD', payload: 2 } }, addAsync: () => { return { type: 'ADD', payload: 2 } } } export default connect( mapStateToProps, mapDispatchToProps )(App);

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {createStore} from 'redux';

import { Provider } from 'react-redux';


let store = createStore(stateChanger);

function stateChanger(state, action) {
    if(typeof state === "undefined") {
        return {
            number: 0
        }
    }
    switch(action.type) {
        case 'ADD':
            return  {
                number: state.number + action.payload
            };
        case 'MINUS':
            return  {
                number: state.number - action.payload
            };
        default:
            return state;
    }
}


render();

store.subscribe(() => {
    render();
})

function render() {
    ReactDOM.render(
    
        
    ,
    document.getElementById('root'));

}

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();

通过一个「Provider」组件把「App」组件包裹住,然后把「store」放在「Provider」组件上。在「App」组件中,最后使用「connect」函数,第一个参数接受「mapStateToProps」和「mapDispatchToProps」。
「mapStateToProps」的作用是是接受父组件传来的「store」并只获取其中部分属性,获得的部分属性供当前组件使用,当前组件可以通过「this.props」调用。
「mapDispatchToProps」是一个「对象」,里面的每个属性就是action,当前组件可以通过「this.props」统一调用。

我们可以log看看「this.props」。


4. Redux是啥?_第2张图片
image.png

大概流程就是,「App.js」中点击按钮,通过「mapDispatchToProps」,然后「index.js」中的「stateChanger」函数来更新「store」,「store」有更新就被「subscriber」监听到,然后重新渲染,固然传入「Provider」的「store」有改变,然后「App.js」中的「mapStateToProps」获取整个「store」的「部分属性」,供当前组件使用,可以使用「this.props」获取「属性值」和「方法」。

你可能感兴趣的:(4. Redux是啥?)