美文网首页
React redux 第二章 高级玩法

React redux 第二章 高级玩法

作者: yanmingfei | 来源:发表于2019-03-31 18:57 被阅读0次

    数据状态交互

    简介

    对于Vue有内置的Vuex来进行数据通信机制,而相对于React有很多的数据通信机制工具。如flux 这是官方推荐,但是它也有自己的不足,后面有大神(非官方)开发了Redux,不过也是得到了官方认可和推荐。

    为什么会有状态管理

    这就要提到React的短板,它也是一个单向数据流,如果想要向父级的父级提交数据,那么就需要父级向下一直传递方法,在当前的组件中调用传递下来的方法,大家可以想像一下,如果有很多级的话该如何做?那么如果还有非父子组件该如何通信? 可以通过全局的订阅和发布来做。

    但这并不是最好的解决方案,那么就可以通过我们简介里面的方法去做,在这里,还是需要给大家列举出组件通信的默认方案吧,让大家对其有个更深刻的了解。

    孙辈级通信

    class Father extends Component {
        static childContextTypes = {
            color: React.PropTypes.string
        };
        getChildContext(){
            return {
                color: 'red'
            }
        }
        constructor (props){
            super(props)
        }
        render (){
            return <div>
                <Child />
            </div>
        }
    }
    class Child extends Component {
        static contextTypes = {
            color: React.PropTypes.string
        }
        render (){
            const {props} = this
            return <div>
                <h1 style={{background: this.context.color}}>This is Child.</h1>
            </div>
        }
    }
    

    可以看出,我们在 Father 组件中并未给 Child 组件中进行传 props ,而是在父组件中定义了,childContext,这样从这一层开始的子组件都可以拿到这个值,需要蓄意的是,使用 context 方式时候,需要写一个 getChildContext 方法来获取这个值。

    兄弟或无关组件间通信

    没有嵌套关系的,那只能通过影响全局的一些机制去实现。这样看,自定义事件机制不失为一种很好的方案。在这边使用了 EventEmitter 模块(npmnode的基础模块)进行通信。

    import React, {Component,PropTypes} from 'react'
    import ReactDom from 'react-dom'
    import {EventEmitter2} from 'eventemitter2'
    
    var emitter = new EventEmitter2()
    
    class First extends Component {
        constructor(props){
            super(props)
            this.state = {
                data: 'init First'
            }
    
            emitter.on('changeFirstText', this.changeText.bind(this))
        }
        changeText( msg ){
            this.setState({
                data: 'First change success: origin ' + msg
            })
        }
        render (){
            return <div>
                <h1>{this.state.data}</h1>
            </div>
        }
    }
    class Second extends Component {
        handleClick(){
            emitter.emit('changeFirstText', 'Second')
        }
        render (){
            return <div onClick={ this.handleClick.bind(this) }>
                <button>点击修改 First 组件内容</button>
            </div>
        }
    }
    

    First 中注册了自定义事件,changeFirstText,并且绑定好回调函。emitter.on('changeFirstText', this.changeText.bind(this))
    在 Second 当用户点击发送信息请求时,在 handleClick 中,触发 changeFirstText 事件,并且把需要的信息传给过去。emitter.emit('changeFirstText', 'Second')

    简单学习一下flux(了解即可)

    React 标榜自己是 MVC 里面 V 的部分,那么 Flux 就相当于添加 MC 的部分。

    Flux 是 Facebook 使用的一套前端应用的架构模式。一个 Flux 应用主要包含四个部分:

    • the dispatcher

      处理动作分发,维护 Store 之间的依赖关系

    • the stores

      数据和逻辑部分

    • the views

      React 组件,这一层可以看作 controller-views,作为视图同时响应用户交互

    • the actions

      提供给 dispatcher 传递数据给 store

    先来了解一下 Flux 的核心“单向数据流“怎么运作的:

    Action -> Dispatcher -> Store -> View
    

    掌握redux

    简介

    如果说flux只是一种思想,那么redux就是对flux的具体实现。我们去学习redux时不要总着眼于概念,我们可以亲自的先使用一下,再去书写一下它的功能,这样大家对其会有一个更深刻的概念,我希望通过这个课程的讲解,为的就是将来能够面试时有个更好的体验。

    使用:

    安装

    npm install --save redux或yarn add redux

    在这期中有四个概念,我们一开始已经有一个状态,也就是我们的view层,即组件层,我们在一开始,先去实现仓库以及Reducers使其建立联系。

    import { createStore } from 'redux'
    function reducer(state = 0, action) {
      switch (action.type) {
       case 'INCREMENT':
          return state + 1
        case 'DECREMENT':
          return state - 1
        default:
          return state
      }
    }
    let store = createStore(reducer)
    store.subscribe(() => console.log(store.getState()))
    store.dispatch({ type: 'INCREMENT' })
    store.dispatch({ type: 'INCREMENT' })
    store.dispatch({ type: 'DECREMENT' })
    

    其中reducer函数我对其官网的翻译直接拿过来给大家来看

    这是一个reducer,一个带有(state,action)=>状态签名的纯函数。它描述了一个操作如何将状态转换为下一个状态。状态的形状取决于您:它可以是一个原语、一个数组、一个对象,甚至是不可变的.js数据结构。唯一重要的部分是,您不应该改变状态对象,而是在状态改变时返回一个新对象。
    在本例中,我们使用“switch”语句和字符串.
    

    对上面的例子,我们当然可以结合 react 的组件进行使用。不过我们还可以进行一个更好的例子,todolist来实现。

    TODOlistui组件
    import React, {Component} from 'react';
    import 'antd/dist/antd.css'
    import * as actions from './Store/actionsCreators'
    import store from './Store';
    import TodoListUi from './TodoListUi'
    import axios from "axios";
    import {initListAction} from "./Store/actionsCreators";
    //容器组件 是聪明组件,UI组件是傻瓜组件,那么可以使用无状态组件。
    export default class TodoList extends Component {
        constructor(props) {
            super(props);
            this.state = store.getState()
            this.Hchange = this.Hchange.bind(this)
            this.HstoreChange = this.HstoreChange.bind(this)
            this.Hremove = this.Hremove.bind(this)
            store.subscribe(this.HstoreChange)
        }
        HstoreChange() {
            this.setState(store.getState())
        }
        Hchange(e) {
            actions.getInputChangeAction(e.target.value)
        }
        Hremove(index) {
            actions.deleteTodoItemAction(index)
        }
        Hadd(e) {
            if (e.keyCode !== 13) return;
            actions.addTodoItemAction();
        }
        render() {
            return (
                <TodoListUi
                    list={this.state.list}
                    Hchange={this.Hchange}
                    Hremove={this.Hremove}
                    Hadd={this.Hadd}
                    inputValue={this.state.inputValue}></TodoListUi>
            );
        }
        async componentDidMount() {
            let res =await axios.get('http://localhost:3000/json/res.json')
            if(!res) return;
            initListAction(res.data)
        }
    }
    
    TodoList组件
    import React, {Component} from 'react';
    import 'antd/dist/antd.css'
    import * as actions from './Store/actionsCreators'
    import store from './Store';
    import TodoListUi from './TodoListUi'
    
    //容器组件 是聪明组件,UI组件是傻瓜组件,那么可以使用无状态组件。
    export default class TodoList extends Component {
        constructor(props) {
            super(props);
            this.state = store.getState()
            this.Hchange = this.Hchange.bind(this)
            this.HstoreChange = this.HstoreChange.bind(this)
            this.Hremove = this.Hremove.bind(this)
            store.subscribe(this.HstoreChange)
        }
        HstoreChange() {
            this.setState(store.getState())
        }
        Hchange(e) {
            actions.getInputChangeAction(e.target.value)
        }
        Hremove(index) {
            actions.deleteTodoItemAction(index)
        }
        Hadd(e) {
            if (e.keyCode !== 13) return;
            actions.addTodoItemAction();
        }
        render() {
            return (
                <TodoListUi
                    list={this.state.list}
                    Hchange={this.Hchange}
                    Hremove={this.Hremove}
                    Hadd={this.Hadd}
                    inputValue={this.state.inputValue}></TodoListUi>
            );
        }
        componentDidMount() {
            const action = actions.getTodoList();
            store.dispatch(action)
        }
    }
    store文件
    //1.先创建数据模型
    
    /*
    import {createStore} from 'redux';
    const store = createStore();
    export default store;
    */
    // 2.管理员什么都不知道需要我新建一个函数reducer.js 返回一个函数,里面传递参数 state和action
    
    import reducer from './reducer'
    
    import {createStore,applyMiddleware} from 'redux';
    import {composeWithDevTools} from 'redux-devtools-extension'
    const store = createStore(
        reducer,
        composeWithDevTools()
    );
    export default store;
    2.reducer文件
    //图书管里面有许多的图书和图书的 权限和方法(借阅/镇馆)
    import * as types from './actionTypes'
    //初始数据模型
    const defaultState  = {
        inputValue:'',
        list:[1,2]
    }
    
    export default (state=defaultState,action)=>{
        if(action.type===types.CHANGE_INPUT_VALUE){
            const newstate = JSON.parse(JSON.stringify(state));
            newstate.inputValue = action.value;
            return newstate;  //固定写法reducer可以接受state,但不能修改state
        }
        if(action.type===types.ADD_TODO_ITEM){
            const newstate = JSON.parse(JSON.stringify(state));
            newstate.list.push(state.inputValue)
            newstate.inputValue = ''
            return newstate;  //固定写法reducer可以接受state,但不能修改state
        }
        if(action.type===types.DELETE_TODO_ITEM){
            const newstate = JSON.parse(JSON.stringify(state));
            newstate.list.splice(action.index,1)
            newstate.inputValue = ''
            return newstate;  //固定写法reducer可以接受state,但不能修改state
        }
        if(action.type===types.INIT_LIST){
            const newstate = JSON.parse(JSON.stringify(state));
            newstate.list= action.arr;
            return newstate;  //固定写法reducer可以接受state,但不能修改state
        }
        return state;
    }
    3.actions
    import * as types from './actionTypes'
    import store from './index';
    import axios from "axios";
    
    
    
    export const getInputChangeAction=(value)=>{
        store.dispatch({
            type:types.CHANGE_INPUT_VALUE,
            value
        })
    };
    export const addTodoItemAction=()=>{
        store.dispatch({
            type:types.ADD_TODO_ITEM
        })
    }
    export const deleteTodoItemAction=(index)=> {
        store.dispatch({
            type:types.DELETE_TODO_ITEM,
            index
        })
    }
    export const initListAction=(arr)=> {
        store.dispatch({
            type:types.INIT_LIST,
            arr
        })
    }
    4.antionsTypes
    export const CHANGE_INPUT_VALUE='CHANGE_INPUT_VALUE';
    export const ADD_TODO_ITEM = 'ADD_TODO_ITEM';
    export const DELETE_TODO_ITEM = 'DELETE_TODO_ITEM'
    export const INIT_LIST = 'INIT_LIST'
    

    上面案例如能跟上来那么就需要我们对其有个好的了解。接下来我们要实现一个功能即我们要进行手写redux简单实现即可。

    相关文章

      网友评论

          本文标题:React redux 第二章 高级玩法

          本文链接:https://www.haomeiwen.com/subject/hkffmqtx.html