Redux

什么是Redux

Redux是JavaScript状态容器,它的诞生是为了给 React 应用提供可预测化的状态管理机制。如果是一个数据状态非常复杂的应用,更多的时候发现React根本无法让两个组件互相交流,使用对方的数据,react的通过层级传递数据的这种方法是非常难受的,这个时候,迫切需要一个机制,把所有的state集中到组件顶部,能够灵活的将所有state各取所需的分发给所有的组件,这就是Redux。
如下图是不使用Redux和使用Redux时,父子组件之间的通信方式;
在这里插入图片描述
如果不用Redux,两个组件之间需要通信的话,可能需要多个中间组件为他们进行消息传递,这样浪费了资源,代码也复杂不易管理维护,而我们要传递state是非常麻烦的,而在Redux中,可以先把数据放在数据仓库中(store-公用状态存储空间),在这里就可以统一管理状态,如果哪个组件用到, 就去store中查找。所有的组件都可以通过action修改store,在store中获取最新状态,然而使用redux就可以很好的去解决组件之间的通信问题。

什么时候需要redux

简单来说如果UI层非常简单,没有很多互动,Redux就没必要,如果用了,反而会增加复杂性。以下情况可以用到:
(1)用户的使用方式复杂;
(2)不同身份的用户有不同的使用方式(比如用户和管理员);
(3)多个用户之间可以协作;
(4)与服务器大量交互,或者使用WebSocket。

从组件方面来看,以下也可以考虑使用Redux:
(1)某个组件的状态,需要共享;
(2)某个状态需要在任何地方都可以拿到;
(3)一个组件需要改变全局状态;
(4)一个组件需要改变另一个组件的状态。

redux有三大准则

1、单一数据源:整个应用的state存储再一个js对象中。
2、只读状态:唯一可以修改状态的方式,就是发送(dispatch)一个动作(Action)。
3、用纯函数去修改状态:为了实现根据action修改state值,我们就需要编写 Reducer,reducer本身是一个纯函数,接收state与action作为参数并返回新的state,纯函数好处在于输入确定,输出也会确定。

以下图来说一下他们之间的关系
在这里插入图片描述
Redux会将整个应用状态(数据)存储到Store中,这个store里面保存一棵状态树(state tree),组件可以派发(dispatch)行为(action)给store,而不是直接通知其它组件,组件改变state的唯一方法是通过调用store的dispatch方法,触发一个action,这个action被对应的reducer处理,于是state完成更新,其它组件可以通过订阅store中的状态(state)来刷新自己的视图。

怎么使用Redux

创建Redux的仓库 store和reducer

redux的工作流程有四个部分,其中最重要的是store这个部分,因为它把所有的数据都放到了store中进行管理,在敲代码的时候,要优先写store。
配置Redux开发环境最快的方法就是安装脚手架工具,需要安装

npm install -g create-react-app

用脚手架创建项目

create-react-app xxx
//启动
npm start

创建store仓库

先安装一个redux-react-

npm install --save redux 先安装

在这里插入图片描述
安装好redux,在src目录下创建一个store文件夹,然后创建一个index.js和reducer.js,编写代码。

//index.js
import { createStore } from 'redux'  // 引入createStore方法
import reducer from './reducer'
const store = createStore()          // 创建数据存储仓库

export default store                
export default (state = defaultState,action)=>{
    console.log(state,action)
    return state
}

其中上面有两个参数:
state:指的是原始仓库的状态。
action:指的是action新传递的状态。
reducer:根据传入的action向store返回新的state

Redux工作流程

1、action:
这个方法用来触发 reducers 里面的处理逻辑。它是一个包含type和data的对象,而action的作用就是告诉状态管理员需要进行怎样的操作,可以理解为指令,需要发出多少动作就有多少指令。

const add =()=>{
	return {
		type:"add",//定义action类型
		data:id,
	}
}

2、store:
用来管理整个应用的状态,store可以理解为一个存储数据的仓库,用来管理state的单一对象。以下为Redux通过createStore整个函数,来生成store对象:

import { createStore } from 'redux';
var store = createStore(fn);
//store.getState():获取state ,经过 reducer 返回了一个新的 state,可以用该函数获取。
var state = store.getState();
//store.dispatch(action):发出 action,用于触发 reducer 更新 state,
store.dispatch({
type:'add',
data:id,
})

3、reducer:
reducer是一个函数,当dispatch之后,getState的状态发生了变化,而Reducer就是用来修改状态的,它接受action和当前state作为参数,根据不同的action做出不同的操作并返回一个新的state,即:(state,action)=>state

const reducer = function (state, action) {
  //dispatch
  return new_state;

//reducer.js
//相当于给store里增加了两个数据。
const defaultState = {
    inputValue: '',
    list: []
  }
  //reducer 可以接受state但是不能修改state
  export default (state = defaultState, action) => {
    if (action.type === 'change_input_value') {
      const newState = JSON.parse(JSON.stringify(state));
      newState.inputValue = action.value;
      return newState
    }
    if (action.type === 'add_input_value') {
      const newState = JSON.parse(JSON.stringify(state));
      newState.list.push(newState.inputValue)  //push新的内容到列表中去
      newState.inputValue = '';
      return newState;
    }
    return state;
  }

todoList.js

//TodoList.js
import React, { Component } from 'react';
import store from './store';
class TodoList extends Component {

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

    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleList = this.handleList.bind(this);
    this.btnClick = this.btnClick.bind(this);
    this.handleStoreChange = this.handleStoreChange.bind(this);
    store.subscribe(this.handleStoreChange)
  }
  handleStoreChange(){
    this.setState(store.getState());
  }
  handleInputChange(e){
    const action = {
      type: 'change_input_value',
      value: e.target.value
    }
    store.dispatch(action);
  }
  handleList(){
    return this.state.list.map((item) => {
      return <li>{item}</li>
    })
  }
  btnClick(){
    const action = {
      type: 'add_input_value',
      value: this.state.inputValue
    }
    store.dispatch(action);
  }
  render() {
    return (
      <div>
        <div>
          <input 
            value = {this.state.inputValue} 
            onChange = {this.handleInputChange}
          />
          <button onClick={this.btnClick}>提交</button>
        </div>
        <ul>
          {this.handleList()}
        </ul>
      </div>
    );
  }
}
export default TodoList;

以上中可以总结几点:
(1)store必须是唯一的,多个store是不允许的,就只能有一个store文件;
(2)只有store能改变自己的内容,Reducer不能改变;
(3)Reducer必须是纯函数。

Redux可将UI和业务逻辑进行拆分写

新建一个组件,把JSX部分和需要引入相关的类库也都复制过来,进行引入;剩下的就需要改造父组件进行传递值。
引入之后的redner函数可以写成:

render(){
	return(
		<TodoListWeb 
 			inputValue={this.state.inputValue}
 			change_input_value={this.change_input_value}
 			btnClick={this.btnClick}
		/ >
	);
}

无状态组件

无状态组件就是一个函数,它不用继承任何的类,也不存在state;把UI组件改成无状态组件可以提高程序性能。
步骤如下:
1、不需要引入React的Component;
2、在我们的UI组件中,里面只返回JSX部分就行;
3、函数传递一个props参数,然后修改里面所有的props,去掉this;

import React from react;
const TodoListUi = function(props){
return(
<div>   </div>
)
}

redux中间件原理及实现

如果提到中间件,可能会想到Express和Koa等服务端框架,但是中间件是干嘛的?中间件通常是运行再收到请求到处理请求之间,可能是实现日志记录这些预处理操作,在Redux中,中间件是运行action发送出去,到达reducer之间的一段代码。

1、先配置Redux-thunk组件

npm i --save redux-thunk 

2、引入applyMiddleware

//引入之后按把thunk放到createStore的第二个参数就行。
const store = createStore(
    reducer,
    applyMiddleware(thunk)
) // 创建数据存储仓库
//如果你要使用中间件,就必须再redux引入applyMiddleware
//compose是使用增强函数
import { createStore , applyMiddleware ,compose } from 'redux'  //  引入createStore方法
import reducer from './reducer'    
import thunk from 'redux-thunk'
//利用compose创造一个增强函数,相当于建立了一个链式函数
const composeEnhancers =   window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}):compose
//有了增强函数,把thunk加入进来,这样两个函数都可以执行
const enhancer = composeEnhancers(applyMiddleware(thunk))
//直接在createStore函数中的第二个参数,使用enhancer变量,相当于两个函数都执行了
const store = createStore( reducer, enhancer) // 创建数据存储仓库
export default store 
)

从最里面看,这里的thunk就是满足redux的中间件实现;如果要使用中间件,就必须在redux中引入applyMiddleware;因为applyMiddleware函数可以接收多个中间件。它可返回一个高阶函数,而这个函数中会初始化store和重写dispatch逻辑,以便后续使用。

componentDidMount(){
    const action = getTodoList()
    store.dispatch(action)
}

现在我们执行这个方法,去修改todoList文件中的componentDidMount代码。
它还有一个中间件叫saga。

React-Redux介绍&安装

React-Redux这是一个React生态中常用组件,它可以简化Redux流程。
安装操作
没安装脚手架工具的跟上面Redux一样,react-react-app
然后安装react-redux

npm install --save react-redux

React-redux将组件分为容器组件和UI组件

1、前者会处理逻辑;
2、后者只负责显示和交互,内部不处理逻辑,状态完全由外部掌控。

两个核心

Provider

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
const App=(
  <Provider store={store}>//包裹的store是提供者的一个属性
        <TodoList />
    </Provider>
)

ReactDOM.render(App, document.getElementById('root'));

这个Provider可以叫做顶层组件,一般我们都将顶层组件包裹在Provider组件中,所有组件就可以在react-redux的控制之下了。这个组件的目的是让所有组件能够访问到Redux中的数据。只要使用了这个组件,组件里的其它所有组件都可以使用store,这也是react-redux的核心组件。但是store必须作为参数放到Provider组件中。

connect

如何简单的去获取store中的数据呢?下面代码中再在TodoList.js文件中。引入connect,它是一个连接器,其实也是一个方法,有了它就可以获取数据。
先引入

//connect连接器在todoList里面写
 import React, { Component } from 'react';
import store from './store'
import {connect} from 'react-redux'

class TodoList extends Component {
    constructor(props){
        super(props)
        this.state = store.getState()
    }
    render() { 
        return (
            <div>
                <div>
                    <input value={this.props.inputValue} 
                    onChange={this.props.inputChange} />
                    <button>提交</button>
                </div>
                <ul>
                    <li>内容</li>
                </ul>
            </div>
            );
    }
}
//映射关系就是把原来的state映射成组件中的props属性。
const stateToProps = (state)=>{
    return {
        inputValue : state.inputValue
    }
}

const dispatchToProps = (dispatch) =>{
    return {
        inputChange(e){
            console.log(e.target.value)
        }
    }
}
export default connect(stateToProps,dispatchToProps)(TodoList);
//stateToProps代表一个映射关系

其实也就是把Redux中的数据映射到React中的props中去。
映射关系做好,剩下的只要进行action的派发和reducer对业务逻辑的编写就可以了。流程基本上都是一样的。

//action
const dispatchToProps = (dispatch) =>{
    return {
        inputChange(e){
            let action = {
                type:'change_input',
                value:e.target.value
            }
            dispatch(action)
        }
    }
}
//reducer
const defalutState = {
    inputValue : 'neirong',
    list :[]
}
export default (state = defalutState,action) =>{
    if(action.type === 'change_input'){
        let newState = JSON.parse(JSON.stringify(state))
        newState.inputValue = action.value
        return newState
    }
    return state
}

connect的作用就是把UI组件和业务逻辑代码分开,然后通过connect再连接到一块,让代码更加清晰和容易维护,这也是React-Redux的优点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值