P07:通过Input体验Redux的流程

Posted wgchen~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P07:通过Input体验Redux的流程相关的知识,希望对你有一定的参考价值。

阐述

本文将要带大家作的就是通过 Input 的改变,体验一下 Redux 的整体流程,是如何编写代码的。我们要实现的是在 TodoListDemo 中,只要文本框中的值改变就 reduxstore 的值就跟着改变,并且随着 Redux 中的 state 值改变,组件也跟着改变。

整个流程就是以前讲过的这个图:

增加 Input 响应事件

如果想 Input 改变,redux 也跟着改变,需要在 Input 组件上增加 onChange 响应事件, 打开 src 目录下的 ToDolist.js 文件,修改具体代码如下:

<Input 
    placeholder=this.state.inputValue 
    style= width:'250px', marginRight:'10px'
    //---------关键代码----start
    onChange=this.changeInputValue
    //---------关键代码----end
/>

写完这一步,还要记得在 constructor 进行 this 的绑定,修改 this 的指向。

constructor(props)
    super(props)
    this.state=store.getState();
    this.changeInputValue= this.changeInputValue.bind(this)

这步完成后,就可以编写 changeInputValue 方法的代码了。
我们先在控制台打印出文本框的变化,代码如下:

changeInputValue(e)
    console.log(e.target.value)

然后打开浏览器,按F 12 看一下控制台的结果。


下面需要作的事就是改变 Redux 里的值了,我们继续向下学习。

源码

import React,  Component  from 'react';
import 'antd/dist/antd.css'
import  Input , Button , List  from 'antd'
import store from './store'

class TodoList extends Component 
    constructor(props)
        super(props)
        this.state=store.getState();
        this.changeInputValue= this.changeInputValue.bind(this)
    
    render()  
        return ( 
            <div style=margin:'10px'>
                <div>
                    <Input 
                        placeholder=this.state.inputValue 
                        style= width:'250px', marginRight:'10px'
                        onChange=this.changeInputValue
                    />
                    <Button type="primary">增加</Button>
                </div>
                <div style=margin:'10px',width:'300px'>
                    <List
                        bordered
                        dataSource=this.state.list
                        renderItem=item=>(<List.Item>item</List.Item>)
                    />    
                </div>
            </div>
         );
    

    changeInputValue(e)
        console.log(e.target.value)
    

export default TodoList;

创建 Action

想改变 Redux 里边 State 的值就要创建 Action 了。

Action 就是一个对象,这个对象一般有两个属性,第一个是对Action的描述,第二个是要改变的值。

changeInputValue(e)
    const action =
        type:'change_input_value',
        value:e.target.value
    

action 就创建好了,但是要通过 dispatch() 方法传递给 store
我们在 action 下面再加入一句代码。

changeInputValue(e)
    const action =
        type:'changeInput',
        value:e.target.value
    
    store.dispatch(action)

这时 Action 就已经完全创建完成了,也和 store 有了联系。

store 的自动推送策略

前面的章节,已经说了 store 只是一个仓库,它并没有管理能力,它会把接收到的 action自动转发给Reducer

我们现在先直接在Reducer中打印出结果看一下。

打开 store 文件夹下面的 reducer.js 文件,修改代码。

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

讲到这里,就可以解释一下两个参数了:

state: 指的是原始仓库里的状态。
action: 指的是action新传递的状态。

通过打印你可以知道,Reducer已经拿到了原来的数据和新传递过来的数据,现在要作的就是改变 store 里的值。我们先判断 type 是不是正确的,如果正确,我们需要从新声明一个变量 newState(记住:Reducer里只能接收state,不能改变state。),所以我们声明了一个新变量,然后再次用return返回回去。

export default (state = defaultState,action)=>
    if(action.type === 'changeInput')
        let newState = JSON.parse(JSON.stringify(state)) //深度拷贝state
        newState.inputValue = action.value
        return newState
    
    return state

让组件发生更新

现在 store 里的数据已经更新了,但是组件还没有进行更新,我们需要打开组件文件TodoList.js,在constructor,写入下面的代码。

constructor(props)
    super(props)
    this.state=store.getState();
    this.changeInputValue= this.changeInputValue.bind(this)
    //----------关键代码-----------start
    this.storeChange = this.storeChange.bind(this)  //转变this指向
    store.subscribe(this.storeChange) //订阅Redux的状态
    //----------关键代码-----------end

当然我们现在还没有这个 storeChange 方法,只要写一下这个方法,并且重新 setState一次就可以实现组件也是变化的。

在代码的最下方,编写 storeChange 方法。

storeChange()
    this.setState(store.getState())

现在浏览器中预览,可以看到组件和Redux中都同步进行了改变。

总结

本文内容比较多,把Redux的流程都走了一遍,如果这节课你能独立作下来,也就算Redux入门了。

可以把本文内容多看两遍,保证把基础知识打扎实,更重要的是一定要动手作,不然你真的学不会的。

demo

初始化项目

1 如果你没有安装脚手架工具,你需要安装一下:

npm install -g create-react-app

2 直接用脚手架工具创建项目

D:  进入D盘
mkdir ReduxDemo           创建ReduxDemo文件夹
cd ReduxDemo              进入文件夹
create-react-app demo01   用脚手架创建React项目
cd demo01                 等项目创建完成后,进入项目目录
npm  start                预览项目

删除 src 里边的所有文件,只留一个 index.js,并且 index.js 文件里也都清空。

安装 Ant Design UI组件

Ant Design 是一套面向企业级开发的UI框架,视觉和动效作的很好。
安装 AntDesign

npm install antd --save

在使用Ant Design时,第一件事就是先引入CSS样式,有了样式才可以让UI组件显示正常。

import 'antd/dist/antd.css'

引入CSS样式之后,可以快乐的使用 antd 里的 <input> 框了,在使用的时候,你需要先引入Input组件。

import  Input  from 'antd'

Chrome 安装插件 Redux-DevTools

安装 Chrome 插件 Redux-DevTools – Redux调试工具

安装 Redux 是javascript应用工具

Redux是一个用来管理数据状态和UI状态的JavaScript应用工具。

在使用Redux之前,需要先用 npm install 来进行安装,打开终端,并进入到项目目录,然后输入。

npm install --save redux react-redux

Redux有3大核心概念:

  • Action
  • Reducer
  • Store

Action 和 Store 都非常好理解,我们可以直接按照其字面意思,将他们理解为 动作储存

Action表示应用中的各类动作或操作,不同的操作会改变应用相应的state状态,说白了就是一个带type属性的对象。

Store则是我们储存state的地方。
我们通过redux当中的createStore方法来创建一个store,它提供3个主要的方法:

import  createStore  from 'redux'  // 引入createStore方法
const store = createStore()          // 创建数据存储仓库
export default store                 //暴露出去

建立好了仓库,但是这个仓库很混乱,这时候就需要一个有管理能力的模块出现,这就是 Reducers。这两个一定要一起创建出来,这样仓库才不会出现互怼现象。

Reducer里更新Store里的state,Reducer接收两个参数:
旧的 state 和 Action,返回一个新的 state,即 (state, action) => newState

创建 Redux

安装好redux之后,在 src 目录下创建一个 store 文件夹,然后在文件夹下创建一个 index.js文件。

D:\\ReactDemo\\demo01\\src\\store\\index.js 就是整个项目的 store 文件

D:\\ReactDemo\\demo01\\src\\store\\index.js

//  引入createStore方法
import  createStore  from 'redux'

// reducer就建立好了后引入到 store 中,再创建 store 时,以参数的形式传递给 store。
import reducer from './reducer'

 // 创建数据存储仓库    
const store = createStore(
				reducer,
				// 配置 Redux Dev Tools
				window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
			  )
			  
export default store   //暴露出去

建立好了仓库,就需要 Reducers 管理模块。

D:\\ReactDemo\\demo01\\src\\store\\reducer.js

const defaultState =   //默认数据
export default (state = defaultState,action)=>  //就是一个方法函数
    return state

state: 是整个项目中需要管理的数据信息

项目目录结构

d/ReactDemo/demo01 (master)

$ ls -al
total 1921
drwxr-xr-x 1 Administrator 197121       0 12月  7 11:32 ./
drwxr-xr-x 1 Administrator 197121       0 12月  7 11:31 ../
drwxr-xr-x 1 Administrator 197121       0 12月  7 11:32 .git/
-rw-r--r-- 1 Administrator 197121     310 12月  7 11:31 .gitignore
drwxr-xr-x 1 Administrator 197121       0 12月 13 18:31 node_modules/
-rw-r--r-- 1 Administrator 197121     948 12月 13 18:31 package.json
-rw-r--r-- 1 Administrator 197121 1547406 12月 13 18:31 package-lock.json
drwxr-xr-x 1 Administrator 197121       0 12月  7 11:32 public/
-rw-r--r-- 1 Administrator 197121    3369 12月  7 11:31 README.md
drwxr-xr-x 1 Administrator 197121       0 12月 13 18:12 src/

d/ReactDemo/demo01/src/store (master)
 
$ ls -al
total 6
drwxr-xr-x 1 Administrator 197121   0 12月 13 18:14 ./
drwxr-xr-x 1 Administrator 197121   0 12月 13 18:12 ../
-rw-r--r-- 1 Administrator 197121 281 12月 13 19:14 index.js
-rw-r--r-- 1 Administrator 197121 430 12月 14 10:41 reducer.js

demo01\\src\\index.js

主文件

import React from 'react';
import ReactDOM from 'react-dom' // 上面两必有

import TodoList from './TodoList'

ReactDOM.render(<TodoList/>,document.getElementById('root'))

demo01\\src\\TodoList.js

组件

import React,  Component  from 'react';
import 'antd/dist/antd.css'
import  Input , Button , List  from 'antd'
import store from './store'

class TodoList extends Component 

    constructor(props)
        super(props)
        this.state=store.getState();
        this.changeInputValue= this.changeInputValue.bind(this)
        //----------关键代码-----------start
        this.storeChange = this.storeChange.bind(this)  //转变this指向
        store.subscribe(this.storeChange) //订阅Redux的状态
        //----------关键代码-----------end
    

    render()  
        return ( 
            <div style=margin:'10px'>
                <div>
                    <Input 
                        placeholder=this.state.inputValue 
                        style= width:'250px', marginRight:'10px'
                        onChange=this.changeInputValue
                    />
                    <Button type="primary">增加</Button>
                </div>
                <div style=margin:'10px',width:'300px'>
                    <List
                        bordered
                        dataSource=this.state.list
                        renderItem=item=>(<List.Item>item</List.Item>)
                    />    
                </div>
            </div>
         );
    

    changeInputValue(e)
        const action =
            type:'change_input_value',
            value:e.target.value
        
        store.dispatch(action)
    

    storeChange()
        this.setState(store.getState())
    


export default TodoList;

demo01\\src\\store\\index.js

store 仓库

//  引入createStore方法
import  createStore  from 'redux'
import reducer from './reducer'

// 创建数据存储仓库
const store = createStore(reducer,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())

//暴露出去
export default store

demo01\\src\\store\\reducer.js

const defaultState = 
    inputValue : 'Write Something',
    list:[
        '早上4点起床,锻炼身体',
        '中午下班游泳一小时'
    ]


export default (state = defaultState,action)=>
    if(action.type === 'changeInput')
        let newState = JSON.parse(JSON.stringify(state)) //深度拷贝state
        newState.inputValue = action.value
        return newState
    
    return state

以上是关于P07:通过Input体验Redux的流程的主要内容,如果未能解决你的问题,请参考以下文章

通过 react-redux 中的 input 标签上传和显示图像文件

P07:博客列表页&底部制作

P07:组件外层包裹原则Fragment 标签的应用

[Redux/Mobx] 说说Redux的实现流程

如何将 input 与 redux 一起使用?

Redux流程分析 传统流程和redux-toolkit的使用