React的菜鸟之路(二):Redux基本使用

  • 安装Redux

npm install --save redux

  • 在 src 目录下新建 store 文件夹,在store中新建 index.js 和 reducer.js 文件。

React的菜鸟之路(二):Redux基本使用

  • 在 index.js 中通过 createStore 方法创建 store,将 reducer 作为参数传给 createStore 方法 (省了一点懒,reducer内容在后面)

// index.js

import { createStore } from "redux";

import reducer from './reducer';

const store = createStore(

    reducer, 

    // 运行 已安装的redux调试工具,可以在Chrome应用商店里面找到(只有科学上网才能找到的哈)

     window.__REDUX_DEVTOOLS_EXTENSION__  &&  window.__REDUX_DEVTOOLS_EXTENSION__()   

)

export default store;

// reducer.js 声明各组件需要的state变量

// state是只读的,能改变state的唯一方式是通过触发action来修改 !!!

const defaultState = {

  inputValue: 'write something',

  list: ['a', 'b', 'c']

}

export default (state = defaultState, action) => {

// 根据组件中传递过来的action.type决定要修改的值

  if (action.type === 'changInput') { 

   // 深拷贝,reducer只接收,不能直接修改state

    let newState = JSON.parse(JSON.stringify(state)) 

    newState.inputValue = action.value

    return newState

  }

  if (action.type === 'addItem') {

    let newState = JSON.parse(JSON.stringify(state))

    newState.list.push(newState.inputValue)

    newState.inputValue = ''

    return newState

  }

  return state

}

  • 在组件中引入store,并与state绑定

import React, {Component} from 'react';

import { Input, Button, List } from 'antd';

import store from '../../store';

 

class TodoList extends Component {

  constructor(props) {

    super(props)

    this.state = store.getState()   //  返回当前store中的state的数据

    //  绑定this

    this.storeChange = this.storeChange.bind(this)

    this.changeInputValue = this.changeInputValue.bind(this)

    this.clickBtn = this.clickBtn.bind(this)

   // 注册监听store,store变化后调用组件的storeChange方法更新组件的state

    store.subscribe(this.storeChange) 

  }

 // store 变化后,更新组件的 state

  storeChange () {

   this.setState(store.getState())

  }

// 方法中声明 action 传递给 store,让 store 去根据 action.type 在 reducer 中做判断,

// 决定将 reducer 中哪个值改为 action.value,并返回一个新 state 让 store 通知组件去更新

  changeInputValue (e) {

    const action = {

      type: 'changInput',

      value: e.target.value

    }

    store.dispatch(action)

  }

  clickBtn () {

    const action = { type: 'addItem'}

    store.dispatch(action)

  }

  render() { 

    return ( 

      <div>

        <div>

          <Input placeholder={this.state.inputValue}  onChange={this.changeInputValue}  />

          <Button type='primary'  onClick={this.clickBtn}>增加</Button>

        </div>

        <div>

          <List bordered

            dataSource={this.state.list}

            renderItem={item=>(<List.Item }>{item}</List.Item>)}

          />

        </div>

      </div>

     );

  }

}

 

export default TodoList;

如果你有耐心一直看到这里,那么就会发现,在组件里面派发了很多action,也有很多的type,当文件多了之后要查找action.type就会变得非常麻烦。

解决方法就是将action以及actionType统一管理:

在store文件夹中新建actionType.js文件,统一管理type

export const CHANGE_INPUT = 'changeInput'

export const ADD_ITEM = 'addItem'

。。。。。

在store文件夹中新建actionCreators.js文件,管理派发的action

// actionCreators.js

import { CHANGE_INPUT, ADD_ITEM} from './actionTypes'; // 导入type

export const changeInputAction = (value) => ({

  type: CHANGE_INPUT,

  value

})

export const addItemAction = () => ({

  type: ADD_ITEM

})

.......

1、在组件里面引入actionCreators.js,还是用上面的代码吼

import React, {Component} from 'react';

import { Input, Button, List } from 'antd';

import store from '../../store';

import { changeInputAction, addItemAction } from '../../store/actionCreators';

 

class TodoList extends Component {

  constructor(props) {

    super(props)

    this.state = store.getState()   //  返回当前store中的state的数据

    //  绑定this

    this.storeChange = this.storeChange.bind(this)

    this.changeInputValue = this.changeInputValue.bind(this)

    this.clickBtn = this.clickBtn.bind(this)

   // 注册监听store,store变化后调用组件的storeChange方法更新组件的state

    store.subscribe(this.storeChange) 

  }

 // store 变化后,更新组件的 state

  storeChange () {

   this.setState(store.getState())

  }

// 方法中声明 action 传递给 store,让 store 去根据 action.type 在 reducer 中做判断,

// 决定将 reducer 中哪个值改为 action.value,并返回一个新 state 让 store 通知组件去更新

  changeInputValue (e) {

    const action = changeInputAction(e.target.value)

    store.dispatch(action)

  }

  clickBtn () {

    const action = addItemAction()

    store.dispatch(action)

  }

  render() { 

    return ( 

     .......

     );

  }

}

 

export default TodoList;

2、在store => reducer.js里面引入actionType.js

import { CHANGE_INPUT, ADD_ITEM } from './actionType'

const defaultState = {

  inputValue: 'write something',

  list: ['a', 'b', 'c']

}

export default (state = defaultState, action) => {

// 根据组件中传递过来的action.type决定要修改的值

  if (action.type === CHANGE_INPUT) { 

   // 深拷贝,reducer只接收,不能直接修改state

    let newState = JSON.parse(JSON.stringify(state)) 

    newState.inputValue = action.value

    return newState

  }

  if (action.type === ADD_ITEM) {

    let newState = JSON.parse(JSON.stringify(state))

    newState.list.push(newState.inputValue)

    newState.inputValue = ''

    return newState

  }

  return state

}

  • Redux 特点

  1. 统一的状态管理,一个应用中只能有一个store
  2. 仓库中管理了一个状态树(stateTree)
  3. store不能直接修改,只能通过派发器(dispatch)派发一个动作(action)
  4. 更新state的逻辑封装在reducer中,reducer只接受state,不能改变state
  5. reducer必须是一个纯函数,最好不在其中调用后端接口
  • 什么时候使用Redux?

如果UI层非常简单,没有很多互动,Redux就是不必要的,用了反而增加复杂性

  1. 用户使用方式非常简单
  2. 用户之间没有协作
  3. 不需要与服务器大量交互,也没有使用Webscoket
  4. 视图层(view)只从单一来源获取数据

Redux 的适用场景:多交互、多数据源。

  1. 用户的使用方式复杂
  2. 不同身份的用户有不同的使用方式(比如普通用户和管理员)
  3. 多个用户之间可以协作
  4. 与服务器大量交互,或者使用webscoket
  5. view要从多个来源获取数据

从组件角度看,如果你的应用有以下场景,可以考虑使用 Redux。

  1. 某个组件的状态需要共享
  2. 某个状态需要在任何地方都可以拿到
  3. 一个组件需要改变全局状态
  4. 一个组件需要改变另一个组件的状态

​​​

 

参考:https://www.cnblogs.com/yuanjili666/p/11578519.html

相关文章: