React Native开发程序员Web前端之路

React 生态之 Redux

2019-05-27  本文已影响19人  zidea
react_and_redux

Redux 初体验

通常会将 Redux 和 React 联系到一起,但是 Redux 不是寄生于 React 上,Redux 可以单独使用,也可以与 React 以外的第三方框架搭配使用。当然Redux 和 React 还是最好的搭配。Redux = Reducer + Flux ,这是 Redux 名字由来,所以不难看出 Redux 还是源于 Flux 而来,Flux 是为了 React 项目状态管理开发出来的。Redux 子所以备受欢迎,因为站在 Flux 肩膀上还回避掉了 Flux 的一些缺点。

现在 Redux 的作者 Dan 都被 Facebook 收了加入了 React 团队。所以 Redux 还是 React 对于状态说要选择。

今天我们可以脱离 React 先学习,学习 Redux
首先创建一个 React 项目,这就是运行 Redux 没有其他,你可以根据需要创建 vue 框架或者感觉 npm init -y 项目引入 rudex 然后 live-server 启动项目也是 OK,不过为了避免麻烦搭建脚手架,而且随后我们还是要回归到 React 上来分享 react-redux。

还是先分享一下 Redux 机制吧。

创建 store

引入 createStore 用于创建 store。

import { createStore } from 'redux';

定义 types 负责输出类型,所有事件(action)的类型都在这里定义,为了就是同样,为了避免不必要麻烦,也就是避免为人的录入错误。

export const FETCH_POSTS = 'FETCH_POSTS';
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const INCREMENT_ASYNC = 'INCREMENT_ASYNC'

导入类型文件,这里我们主要是简单的通过一个计数器来查看

创建 Reducer

import { INCREMENT, DECREMENT } from '../actions/types'

创建 reducer ,reducer 就是一个函数,reducer 接收两个参数 state 和 action,通过 action 更新 state 然后返回一个 state。

function counter(state = 0, action){
    switch(action.type){
        case INCREMENT:
            return state + 1
        case DECREMENT:
            return state - 1
        default:
            return state;
    }
}

通过 createStore 方法来创建一个 store。

let store = createStore(counter);

订阅事件,store 的 getState 方法可以过去状态 state。

store.subscribe(()=> console.log(store.getState()))

派发事件

store.dispatch({type:INCREMENT})

store.dispatch({type:INCREMENT});

store.dispatch({type:DECREMENT});
let store = createStore(counter);

完整代码

import React, { Component } from 'react';
import { createStore } from 'redux';

import { INCREMENT, DECREMENT } from '../actions/types'

function counter(state = 0, action){
    switch(action.type){
        case INCREMENT:
            return state + 1
        case DECREMENT:
            return state - 1
        default:
            return state;
    }
}

let store = createStore(counter);

store.subscribe(()=> console.log(store.getState()))

store.dispatch({type:INCREMENT})

store.dispatch({type:INCREMENT});

store.dispatch({type:DECREMENT});


window.store = store;

export default class ReduxPage extends Component{
    render(){
        return(
            <div>
                <h1>Redux Demo</h1>
            </div>
        )
    }
}

我们先看一看为什么 React 需要 Redux 呢?

export default class index extends Component {
    constructor(){
        super();
        this.state = {
            tut:"angularjs"
        }
    }

    updateTut(newTut){
        this.setState({
            tut:newTut
        });
    }
    render() {
        return (
            <div>
                <Main changeTut={this.updateTut.bind(this)}/>
                <Tut tut={this.state.tut}/>
            </div>
        )
    }
}

上面代码 state 散落到 React 应用的各个角落不利于管理。Tut 接受 this.state.tut 然后 Main 由更新了 state

 const Main = (props) => {
        return (
            <div>
                <button
                    onClick={()=>props.changeTut('angular')}>
                        update angular
                    </button>
            </div>
        )
}

这样一来缺乏统一管理,对于小型应用我们可以凭借良好记忆,但是对于大型应用,这样势必是难于维护和扩展的。

其实从上面代码来看,redux 并没有那么复杂,就是一个对订阅和发布设计模式实现的框架。当然没有那么简单,但是无论他有多复杂其本质就是订阅和发布模式。

现在我们开始整合到 react 中,首先不使用 react-redux 直接。

先定义事件的类型

export const SET_NAME = "SET_NAME";
export const  SET_TUT = "SET_TUT";

export const ADD = "ADD";
export const SUBTRACT = "SUBTRACT";

定义事件类型,通常是全部大写,单词用 _ 进行分割,以动词开头动词加名称的结构。

定义 Actions

import {SET_NAME,SET_TUT} from "../reducers/types";
 export function setName(name){
     return{
         type:SET_NAME,
         payload:name
     }
 }

 export function setTut(tut){
    return{
        type:SET_TUT,
        payload:tut
    }
}

定义 Reducers

其实 reducer 也可以理解为一个规则定义器。制定 action 是如何更新 state 的规则。

import {SET_NAME,SET_TUT} from "./types"
const userReducer = (state = {
    name:"zidea",
    tuts:50
  }, action) => {
    switch (action.type) {
        case SET_NAME:
            state = {
                ...state,
                name:action.payload
            }
            break;
  
        case SET_TUT:
            state = {
                ...state,
                tuts:action.payload
            }
  
            break;
    }
  
    return state;
  }

  export default userReducer

创建 store 对象

import { createStore,combineReducers,applyMiddleware } from 'redux';

import logger from 'redux-logger'

import math from '../reducers/mathReducer';
import user from '../reducers/userReducer'

import thunk from 'redux-thunk';
import promise from 'redux-promise';

const mLogger = (store) => (next) => (action) => {
    console.log("Logged Action: ", action);
    next(action)
 }
 
 const store = createStore(combineReducers(
     {
         math,
         user
        }),
   {},
   applyMiddleware(mLogger,logger,thunk,promise));


   export default store;

将 store 与应用关联

import AppWithRedux from './AppWithRedux'

import {Provider} from 'react-redux';
import store from './AppWithRedux/store'

function App() {
  return (
    <Provider store={store}>

    <div className="App">
      {/* <AdvApp/> */}

      <AppWithRedux/>
    </div>
    </Provider>
  );
}

export default App;

-通过 react-redux 提供 Provider 可以将 store 共享到整个应用中去。

重写组件,组件与 Redux 关联

import React, { Component } from 'react'
import Tut from '../AppWithoutRedux/components/Tut';
import Main from '../AppWithoutRedux/components/Main';


import {Provider,connect} from 'react-redux'
import {setName} from "./actions/userActions";


class index extends Component {
    constructor(){
        super();
       
    }

    updateTut(newTut){

    }
    
    render() {
        return (
            
            <div>
                <h1>React 和 Redux</h1>
                <Main changeTut={() => this.props.setName('tina')}/>
                <Tut tut={this.props.user.name}/>
            </div>
        )
    }
}

const mapStateToProps = (state) => {
    return {
        user:state.user,
        math:state.math
    }
}

const mapDispatchToProps = (dispatch) => {
    return{
        setName:(name)=>{
            dispatch(setName(name))
        }
    }
}

export default connect(mapStateToProps,mapDispatchToProps)(index)

从 react-redux 引入 connect 负责将组件和 redux 相关联。关联接受两个 mapStateToProps 和 mapDispatchToProps。当然可以根据自己喜好起其他名称,

现在问题是 store 的订阅是在哪里做的呢?也就是 subscribe 方法怎么实现的。

无需 redux-react 实现 redux 管理组件状态

import {Provider,connect} from 'react-redux'
constructor(props){
    super(props);
    this.state = { counter: store.getState()}
    
    store.subscribe(()=> this.setState({
        counter:store.getState()
    }))
    this.increment = this.increment.bind(this);
    this.decrement = this.decrement.bind(this);
}
increment(){
    store.dispatch({type:INCREMENT});
}

decrement(){
    store.dispatch({type:DECREMENT});
}
export default class ReduxPage extends Component{
    constructor(props){
        super(props);
        this.state = { counter: store.getState()}
        
        store.subscribe(()=> this.setState({
            counter:store.getState()
        }))
        this.increment = this.increment.bind(this);
        this.decrement = this.decrement.bind(this);
    }

    increment(){
        store.dispatch({type:INCREMENT});
    }

    decrement(){
        store.dispatch({type:DECREMENT});
    }
    render(){
        return(
            <div>
                <h1>Redux Demo</h1>
                <p>{this.state.counter}</p>
                <div>
                    <button 
                        onClick={this.increment}
                        >increment</button>
                    <button
                        onClick={this.decrement}
                        >decrement</button>
                </div>
            </div>
        )
    }
}

我们将 redux 从项目抽离出来,作为组件单独来使用,store 作为组件 props 属性传入到组件

return(
    <div>
        <h1>Redux Demo</h1>
        <Counter store={store}/>
    </div>
)

定义组件,在组件构造函数里处理订阅事件。

constructor(props){
    super(props);
    console.log(props)
    this.state = {
        counter: props.store.getState()
    }

    props.store.subscribe(()=> this.setState({
        counter:props.store.getState()
    }))
    this.increment = this.increment.bind(this);
    this.decrement = this.decrement.bind(this);
}

应用端完整代码

import React, { Component } from 'react';
import { createStore } from 'redux';

import { INCREMENT, DECREMENT } from '../actions/types'
import Counter from '../components/Counter';

function counter(state = 0, action){
    switch(action.type){
        case INCREMENT:
            return state + 1
        case DECREMENT:
            return state - 1
        default:
            return state;
    }
}

let store = createStore(counter);

export default class ReduxPage extends Component{
    constructor(props){
        super(props);
    }

    render(){
        return(
            <div>
                <h1>Redux Demo</h1>
                <Counter store={store}/>
            </div>
        )
    }
}

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { INCREMENT, DECREMENT } from '../actions/types'

class Counter extends Component {

    constructor(props){
        super(props);
        console.log(props)
        this.state = {
            counter: props.store.getState()
        }

        props.store.subscribe(()=> this.setState({
            counter:props.store.getState()
        }))
        this.increment = this.increment.bind(this);
        this.decrement = this.decrement.bind(this);
    }

    increment(){
        this.props.store.dispatch({type:INCREMENT});
    }

    decrement(){
        this.props.store.dispatch({type:DECREMENT});
    }

    render(){
        return(
            <div>
                <p>{this.state.counter}</p>
                <div>
                    <button 
                        onClick={this.increment}
                        >increment</button>
                    <button
                        onClick={this.decrement}
                        >decrement</button>
                </div>
            </div>
        )
    }
}


export default Counter;

希望我的分享对大家有所帮助。

react 生态
上一篇下一篇

猜你喜欢

热点阅读