Redux 入门级教学文档

Redux 入门级教程文档

在这里我将用最浅显易懂的语言给小伙伴们解释一下 Redux, 并且一步步的教大家如何使用 Redux

一、概念说明

1、什么是 Redux, 为什么要使用 Redux

官网说明:Redux 是 JavaScript 状态容器,提供可预测化的状态管理。

什么意思呢?就是说随着页面复杂化,页面上的很多数据需要保存,若路由跳转后,前一个页面的数据被销毁会导致数据的丢失。

若通过 url 传递,十分的麻烦,且要将每个数据传入组件中,写起来也是十分的无脑浪费时间。

2、为什么要使用 Redux

如果有个仓库用来保存整个项目中需要被保留的数据,且组件中可以直接拿到仓库的数据。那么这些数据将时刻保持一致,且清晰。

二、环境搭建

1、安装

首先我们先用 create-react-app 创建一个 react 项目。

create-react-app redux-text,

安装 redux

npm install --save redux 或者 yarn add redux

npm install --save react-redux 或者 yarn add react-redux

2、概念简单说明

这里有几个概念需要大家先稍微知道以下:

store: 我们存放整个项目的一个仓库,一个项目只能有一个仓库,用来存放需要保存的数据。

state: store 中保存的数据。

action: 用户在页面上的操作是修改不到 store 里的 state。页面上的 view 要发生变化,就要在页面上通过 action,去告诉 state 你要变化了。注意:这里的 action 只是告诉仓库的数据要变化了,而不是去变化数据!!

reducer: 接收 action 的请求,执行修改 store 里的 state 的变化。

3、目录结构

接下来我们来创建几个项目中需要用到的文件夹和文件,以下是目录结构:

.
├── .gitignore
├── README.md
├── src                         
│   └── action                  	
│     ├── oneAction.js		
│     ├── twoAction.js		
│   └── components			
│   └── container
│			├── pageOne
|       ├──index.js
│   └── reducer	
│     ├── oneReducer.js
│     ├── twoReducer.js
│     ├── index.js
│   └── App.css		
│   └── App.js		
│   └── .....       
├── node_modules
├── package.json                
├── public            

三、搭建数据源

创建两个数据源:

src/reducer/oneReducer.jssrc/reducer/twoReducer.js

const oneReducer = (
  state = {
    name: '航航',
    address: '福州'
  },
  action
) => {
  switch(action.type) {
    case 'setName': 
      return {
        ...state,
        name: action.payload.name
      }
    default: 
    return state;
  }
}

export default oneReducer;

这里的纯函数 oneReducer(state, action) 的两个参数,分别代表了 store 下, 名为 oneReducerstateaction

state: 存放了 oneReducer 下的所有数据源和初始值。

action: 通过不同的 action.type 去执行不同的操作,修改 state 数据

注意:每次修改 state, redux 并不是去修改原来的 state,而是返回一个新的 state, 用新的 state, 去替换旧的 state

action.typesetName 时,我们先将原先的 state 解构出来,并给 name 附上新值。

twoReducer.js 也是如此:

const twoReducer = (
  state = {
    age: 10,
  },
  action
) => {
  switch(action.type) {
    case 'setAge':
      return {
        ...state,
        age: 11,
      }
    default: 
    return state;
  }
}

export default twoReducer;

最后一步,整合所有的 reducer

import { combineReducers } from 'redux';

import OneReducer from './oneReducer';
import TwoReducer from './twoReducer';

export default combineReducers({
  OneReducer,
  TwoReducer,
})

combineReducers: 将所有的子 reducer 函数组成对象,提供一个新的 Reducer 函数

四、编写页面

我们写一个简单的页面,将两个数据源的数据都展示出来。

1、创建仓库

打开 src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import * as serviceWorker from './serviceWorker';
import PageOne from './container/pageOne';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import Reducer from './reducer';

const store = createStore(Reducer);

ReactDOM.render(
  <Provider store={store}>
    <PageOne/>
  </Provider>
, document.getElementById('root'));

serviceWorker.unregister();

createStore: 创建仓库,用来存放 recuder 下的所有数据源。

Provider: redux 提供的一个组件,将 store 传递给其自组件。简单说就是在整个项目的最外层包上一个组件,放进一个 store, 这样就将 store 绑定进了项目中。

2、展示页面

那么现在我们来专注于页面 /src/container/pageOne/index.js 的编写:

import React from 'react';
import { connect } from 'react-redux';

class PageOne extends React.Component {
  render() {
    const { oneReducer, twoReducer } = this.props;
    const { name = '', address = '' } = oneReducer;
    const { age = 0 } = twoReducer;
    console.log(oneReducer, twoReducer);
    return (
      <div>
        <div>name: {name}</div>
        <div>address: {address}</div>
        <div>age: {age}</div>
      </div>
    )
  }
}

const mapStateToProps = state => {
  const { oneReducer, twoReducer } = state;
  return {
    oneReducer,
    twoReducer,
  }
}

export default connect(mapStateToProps)(PageOne);

细细讲解以下上面的知识点哈:

mapStateToProps: 获取 store 仓库下的数据源,这里可以打印以下 state, 看下输出。

connect: 由 React Redux 库提供的方法,将当前 Redux store state 映射到展示组件 props 中。

connect 做了性能优化,可以避免很多不必要的重复渲染,比如,当 state 数据变动时,不必编写 shouldComponentUpdate 方法来更新展示数据。

那么至此,仓库中的数据我们就可以通过 this.props 获取到。

3、修改仓库数据

store 的数据是无法被修改的,这个保证了数据的稳定性。所以 redux 抛出一个 store.dispatch(action) 的事件,提供用户修改 store 数据。

所以我们继续修改上面的 pageOne/index.js 页面(简写):

class PageOne extends React.Component {
  
  changeName = (val) => {
    this.props.dispatch({
      type: 'setName',
      payload: {
        name: val
      }
    })
  }

  render() {
    return (
      <div>
        <div>name: {name}</div>
        <div>address: {address}</div>
        <div>age: {age}</div>
        <button onClick={ () => { this.changeName('change_name') }}>修改名字</button>
      </div>
    )
  }
}

现在去尝试以下执行按钮点击事件吧。

好了,那么至此一个状态管理的操作就完成了。细心的小伙伴会发现 action 好像没有用到?

那么这个 action 到底是做什么的?

在我理解,就是把 dispatch 中的内容放到 action 中。

五、编写 action

编写 src/action/oneAction.js

export const setName = (name) => ({
  type: 'setName',
  payload: {
    name,
  }
})

export const setAge = (age) => ({
  type: 'setAge',
  age
})

修改下 pageOne/index.js 页面(简写):

import { setName } from '../../action/oneAction';

class PageOne extends React.Component {
  changeName = (val) => {
    this.props.dispatch(setName(val))
  }
  ...
}

执行以下操作是不是发现也可以呢?那么为什么我们还要来编写 action 呢?

在我理解:是为了更加注重 MVC 的模式,View 就应该注重 View 的展示逻辑,所以与 UI 无关的逻辑操作就交给 redux 来处理,体现代码分层、职责分离的编程思想。

六、中间件-异步

1、代码操作(第2点是知识点讲解,小伙伴们要看哈)

由于很多时候执行dispatch并不仅仅是立即去更新reducer,这时需要执行其他函数来满足项目需求,这些函数就是中间件,最后执行过一系列中间件后再去执行reducer

如果我们调取服务端的接口,存在时间的延迟;或者说我想在 reducer 中也去调取其他 reducer 的操作,行不行?

我们来实验一下:

我们 oneAction.js 文件中再增加一个方法:

export const allChange = () => dispatch => {
  dispatch(setName('all_hang'));
  dispatch(setAge(10010));
}

pageOne.js 页面上增加一个点击事件(简写):

import { setName, allChange } from '../../action/oneAction';

class PageOne extends React.Component {

  changeAll = () => {
    this.props.dispatch(allChange())
  }

  render() {
    return (
      ...
      <div>
        <button onClick={ () => { this.changeAll() }}>修改全部</button>
      </div>
      ...
    )
  }
}

当我们点击按钮就发现报错了。看下 console 的报错信息: Use custom middleware for async actions. 翻译过来的意思是:使用自定义中间件进行异步操作。

说明在 reducer 中调用别的 reducer 的方法是可以的,但是因为我们缺少中间件,所以执行报错,现在我们来把中间件加上:

修改代码前我们要编辑 cli,新增一条命令

yarn add redux-thunknpm install --save redux-thunk 导入 redux-thunk 库。

编辑 src/index.js(简写):

以下为简写代码,页面上原先的内容不删除,只是新增了几行代码和修改了 createStore

import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';

const store = createStore(
  Reducer,
  applyMiddleware(
    thunkMiddleware
  )
);
...
...

那么现在去执行以下 allChange() 事件看看效果,是不是发现页面不报错了,且 nameage 的数据也已经做了修改。

2、知识点

那么我们来讲解以下 applyMiddlewarethunkMiddleware

什么是 middleware

reduxmiddleware 是 发送 actionaction 到达 reducer 之间的第三方扩展,middleware 是架在 actionstore 之间的一座桥梁。

applyMiddleware 可以看看官网的解释。

Middleware 可以让你包装 storedispatch() 方法来达到你想要的目的。

3、补充

最后来一个补充:

如果你想每次 dispatch 都能够在 console 打印日志的话,手写会非常的繁琐。

那么 redux 也提供了这样一个中间件,帮助我们打印日志。

键入 yarn add redux-logger 或者 npm install --save redux-logger 来导入 redux-logger 库。

src/index.js 下加入以下代码:

import { createLogger } from 'redux-logger'

const loggerMiddleware = createLogger()

const store = createStore(
  Reducer,
  applyMiddleware(
    thunkMiddleware,
    loggerMiddleware
  )
);

好了,去尝试一下吧~

记得双击么么哒~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值