React redux 第二章 高级玩法

2019-03-31  本文已影响0人  yanmingfei

数据状态交互

简介

对于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 应用主要包含四个部分:

先来了解一下 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简单实现即可。

上一篇下一篇

猜你喜欢

热点阅读