通过一个案例学习Redux+React-Redux+Redux-Thunk在React项目中的基本使用

一、需求描述及分析

在一个页面中有三个组件,分别为HeaderList以及AddForm,它们是兄弟组件,要求:

  • Header组件中有两个按钮(一个同步一个异步)可以打开AddForm(默认AddForm隐藏不显示)
  • AddForm有一个按钮可以关闭自身
  • AddForm中有输入框,可以添加数据到List组件
  • List可以显示数据

需求中的数据流如下图所示:
在这里插入图片描述

二、案例实操

1. 安装依赖

  • 安装redux(核心库)
npm install redux
  • 安装react-redux(用于实现React中的props与redux的映射)
npm install react-redux
  • 安装redux-thunk(用于支持异步action)
npm install --save redux-thunk
  • 安装redux-devtools-extension(用于在开发者工具中查看状态变化)
npm install redux-devtools-extension -D

2. 项目目录

在这里插入图片描述

3. 准备action的type名称的常量

constant.js

/* 
	该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
*/
export const OPEN_FORM = 'openForm'
export const CLOSE_FORM = 'closeForm'
export const ADD_DATA = 'addData'

4. 编写action的生产工厂

src\store\actions\form.js

/* 
	该文件专门为Form组件生成相关action对象
*/
import {OPEN_FORM,CLOSE_FORM} from '../constant'

// 同步action,就是指action的值为Object类型的一般对象
export const openForm = data => ({type:OPEN_FORM,data}) //打开添加表单的同步action对象
export const closeForm = data => ({type:CLOSE_FORM,data}) // 关闭表单的同步action

// 异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const openFormAsync = data => {
    // 返回一个函数,参数是dispatch函数,函数里面包含异步操作,且一般要调用同步action
    return (dispatch) => {
        setTimeout(() => {
            dispatch(openForm(data))
        },2000)
    }
}

src\store\actions\list.js

/* 
	该文件专门为List组件生成相关action对象
*/
import {ADD_DATA} from '../constant'

// 同步action
export const addData = data => ({type:ADD_DATA,data})

5. 编写reducers

当有多个reducer时,需要使用combineReducers()函数将其合并为一个

src\store\reducers\form.js

import {OPEN_FORM,CLOSE_FORM} from '../constant'
/**
 * form组件的reducer
 */
// 初始状态
let initSate = {
    isOpen:false //是否打开表单
}
export default function formReducer(state=initSate,action){
    console.log(action)
    switch(action.type){
        case OPEN_FORM: // 显示表单
            return {...state,isOpen:true} // 注意更新状态的写法
        case CLOSE_FORM: // 隐藏表单
            return {...state,isOpen:false}
        default:
            return state
    }
}

src\store\reducers\list.js

import {ADD_DATA} from '../constant'

// 初始状态
const initSate = {
    list:[]
}

export default function listReducer(state=initSate,action){
    switch(action.type){
        case ADD_DATA:
            return {...state,list:[...state.list,action.data]} // 注意更新状态的写法
        default:
            return state
    }
}

src\store\reducers\index.js

/* 
	该文件用于汇总所有的reducer为一个总的reducer
*/
//引入combineReducers,用于汇总多个reducer
import {combineReducers} from 'redux'
//引入为form组件服务的reducer
import form from './form'
//引入为list组件服务的reducer
import list from './list'

//汇总所有的reducer变为一个总的reducer
export default combineReducers({
	form,
    list
})

6.编写store

src\store\store.js

/* 
	该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/
// 引入createStore,专门用于创建Redux最为核心的store对象
import {applyMiddleware, createStore} from 'redux'
// 引入汇总后的reducer
import reducer from './reducers'
// 引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
// 引入redux开发工具
import {composeWithDevTools} from 'redux-devtools-extension'

// 暴露store,并将对开发者工具和redux-thunk的支持添加进去
export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))

到目前为止,都是在使用Redux的提供的api,并未使用react-redux

7. 更改入口文件

src\index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {Provider} from 'react-redux'
import store from './store/store'
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>
    ,
  document.getElementById('root')
);

要使用Provider组件包裹App组件,并将store对象作为props传递进去,此api由react-redux提供

8. 编写各个组件

使用react-redux提供的connect函数将普通组件包装为容器
关于connect:https://segmentfault.com/a/1190000015042646

  • src\components\Main\Header.jsx
import React, { Component } from 'react'
// 引入connect高阶函数
import {connect} from 'react-redux'
// 引入form的action对象,进而操作form的显示与隐藏
import {openForm,openFormAsync} from '../../store/actions/form'


class Header extends Component {
    /**
     * 同步打开表单
     */
    openForm = () => {
        // 在props中调用映射后的函数,即可更改状态
        this.props.openForm(null)
    }

    /**
     * 异步打开表单
     */
    openFormAsync = () => {
        this.props.openFormAsync(null)
    }

    /**
     * render
     * @returns 
     */
    render() {
        return (
            <div>
                <h3>Header</h3>
                <button onClick={this.openForm}>同步打开表单</button>
                <button onClick={this.openFormAsync}>异步打开表单</button>
            </div>
        )
    }
}

// 通过connect函数进行包装
export default connect(
    state => ({

    }),
    {openForm,openFormAsync} // 第二个参数传入对象可省略不写dispatch函数
)(Header)
  • src\components\Main\List.jsx
import React, { Component } from 'react'
// 引入react-redux的connect函数
import {connect} from 'react-redux'

class List extends Component {
    render() {
        return (
            <div>
                <h3>List</h3>
                <ul>
                    {
                        this.props.list.map(item => {
                            return <li>{item}</li>
                        })
                    }
                </ul>
            </div>
        )
    }
}
export default connect(state => ({list:state.list.list})  // 状态映射
        ,
        {}) // 操作映射
        (List)
  • src\components\Main\AddForm.jsx
import React, { Component } from 'react'
// 引入react-redux的connect函数
import {connect} from 'react-redux'
// 引入相关action,用于状态更新
import {closeForm} from '../../store/actions/form'
import {addData} from '../../store/actions/list'

class AddForm extends Component {

    /**
     * 组件状态
     */
    state = {
        inputValue : ''
    }

    /**
     * 关闭表单
     */
    closeForm = () => {
        // 在props中调用更新redux状态的函数
        this.props.closeForm(null);
    }

    /**
     * 添加数据
     */
    addData = () => {
        this.props.addData(this.state.inputValue)
    }

    /**
     * 处理输入框变化
     */
    handleChange = (e) => {
        this.setState({inputValue:e.target.value})
    }

    render() {
        console.log(this.props.isOpen)
        if(this.props.isOpen){
            return (
                <div>
                    <h3>Form</h3>
                   <input onChange={e => this.handleChange(e)}/>
                   <button onClick={this.addData}>添加</button> 
                   <button onClick={this.closeForm}>关闭表单</button>
                </div>
            )
        } else {
            return (
                <div/>
            )
        }
       
    }
}

export default connect(
    state => ({
        isOpen:state.form.isOpen // 将props与redux中的状态建立映射关系
    }),
    {closeForm,addData}
)(AddForm)

AddForm组件所展示的写法更全面一些

  • src\components\Main\index.jsx
import React, { Component } from 'react'

import AddForm from './AddForm'
import Header from './Header'
import List from './List'
import './index.scss'

export default class Main extends Component {
    render() {
        return (
            <div className='main'>
                <Header/>
    <br/>
                <List/>
                <br/>          
                <AddForm/>
            </div>
        )
    }
}

9. 效果展示

  • Header控制AddForm的显示(同步+异步)
    在这里插入图片描述
  • AddForm关闭自身
    在这里插入图片描述
  • AddForm添加数据
    在这里插入图片描述

使用函数钩子:https://blog.csdn.net/weixin_47967031/article/details/120155872

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值