React(8)—— Redux - 三大核心概念 - store - reducer - actionn - Redux调试工具 - React-redux - 纯函数 - 高阶函数

更多面试题

**《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】


  1. 明确:延迟的动作不想交给组件自身,想交给action

  2. 何时需要异步action:想要对状态进行操作,但是具体的数据靠异步任务返回。

  3. 具体编码:

①npm install redux-thunk,并配置在store中

②创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务。

③异步任务有结果后,分发一个同步的action去真正操作数据。

  1. 备注:异步action不是必须要写的,完全可以自己等待异步任务的结果了再去分发同步action。

六、react-redux

================================================================================

1. 理解


  1. 一个React插件库

  2. 专门用来简化React应用中使用redux

2. react-redux将所有组件分成两大类


  1. UI组件

①只负责 UI 的呈现,不带有任何业务逻辑

②通过props接收数据(一般数据和函数)

③不使用任何 Redux 的 API

④一般保存在components文件夹下

  1. 容器组件

①负责管理数据和业务逻辑,不负责UI的呈现

②使用 Redux 的 API

③一般保存在containers文件夹下

模型图

在这里插入图片描述

3. 相关API


  1. Provider:让所有组件都可以得到state数据

  2. connect:用于包装 UI 组件生成容器组件

  3. mapStateToprops:将外部的数据(即state对象)转换为UI组件的标签属性

  4. mapDispatchToProps:将分发action的函数转换为UI组件的标签属性

4. 基本使用


安装

npm install react-redux

在这里插入图片描述

components/Count/index.jsx

UI组件

import React, { Component } from ‘react’

export default class Count extends Component {

//加法

increment = ()=>{

const {value} = this.selectNumber

this.props.jia(value*1)

}

//减法

decrement = ()=>{

const {value} = this.selectNumber

this.props.jian(value*1)

}

//奇数再加

incrementIfOdd = ()=>{

const {value} = this.selectNumber

if(this.props.count % 2 !== 0){

this.props.jia(value*1)

}

}

//异步加

incrementAsync = ()=>{

const {value} = this.selectNumber

this.props.jiaAsync(value*1,500)

}

render() {

//console.log(‘UI组件接收到的props是’,this.props);

return (

当前求和为:{this.props.count}

<select ref={c => this.selectNumber = c}>

1 2 3

 

当前求和为奇数再加 

异步加 

)

}

}

containers/Count/index.jsx

容器组件

//引入Count的UI组件

import CountUI from ‘…/…/components/Count’

//引入action

import {

createIncrementAction,

createDecrementAction,

createIncrementAsyncAction

} from ‘…/…/redux/count_action’

//引入connect用于连接UI组件与redux

import {connect} from ‘react-redux’

/*

1.mapStateToProps函数返回的是一个对象;

2.返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value

3.mapStateToProps用于传递状态

*/

function mapStateToProps(state){

return {count:state}

}

/*

1.mapDispatchToProps函数返回的是一个对象;

2.返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value

3.mapDispatchToProps用于传递操作状态的方法

*/

function mapDispatchToProps(dispatch){

return {

jia:number => dispatch(createIncrementAction(number)),

jian:number => dispatch(createDecrementAction(number)),

jiaAsync:(number,time) => dispatch(createIncrementAsyncAction(number,time)),

}

}

//使用connect()()创建并暴露一个Count的容器组件

export default connect(mapStateToProps,mapDispatchToProps)(CountUI)

App.jsx

给容器组件传递store

import React, { Component } from ‘react’

import Count from ‘./containers/Count’

import store from ‘./redux/store’

export default class App extends Component {

render() {

return (

{/* 给容器组件传递store */}

)

}

}

总结

  1. 明确两个概念:

①UI组件:不能使用任何 redux 的api,只负责页面的呈现、交互等。

②容器组件:负责和 redux 通信,将结果交给UI组件。

  1. 如何创建一个容器组件————靠 react-redux 的 connect 函数

connect( mapStateToProps, mapDispatchToProps ) (UI组件)

mapStateToProps: 映射状态,返回值是一个对象

mapDispatchToProps: 映射操作状态的方法,返回值是一个对象

  1. 备注1:容器组件中的store是靠props传进去的,而不是在容器组件中直接引入

  2. 备注2:mapDispatchToProps,也可以是一个对象

5. 优化


优化1: 简写mapDispatchToProps

//使用connect()()创建并暴露一个Count的容器组件

export default connect(

state => ({count:state}),

//mapDispatchToProps的一般写法

/* dispatch => ({

jia:number => dispatch(createIncrementAction(number)),

jian:number => dispatch(createDecrementAction(number)),

jiaAsync:(number,time) => dispatch(createIncrementAsyncAction(number,time)),

}) */

//mapDispatchToProps的简写

{

jia:createIncrementAction,

jian:createDecrementAction,

jiaAsync:createIncrementAsyncAction,

}

)(CountUI)

优化2: Provider

容器组件可以检测redux中的状态改变,并渲染页面,所以不需要在index.js中检测了

不要在App.jsx中给子组件传递store了

index.js

import React from ‘react’

import ReactDOM from ‘react-dom’

import App from ‘./App’

import store from ‘./redux/store’

import {Provider} from ‘react-redux’

ReactDOM.render(

,

document.getElementById(‘root’)

)

优化3: 整合UI组件和容器组件

每个组件两个文件夹太麻烦了,直接整合在一起就好了!

containers/Count/index.jsx

import React, { Component } from ‘react’

//引入action

import {

createIncrementAction,

createDecrementAction,

createIncrementAsyncAction

} from ‘…/…/redux/count_action’

//引入connect用于连接UI组件与redux

import {connect} from ‘react-redux’

//定义UI组件

class Count extends Component {

state = {carName:‘奔驰c63’}

//加法

increment = ()=>{

const {value} = this.selectNumber

this.props.jia(value*1)

}

//减法

decrement = ()=>{

const {value} = this.selectNumber

this.props.jian(value*1)

}

//奇数再加

incrementIfOdd = ()=>{

const {value} = this.selectNumber

if(this.props.count % 2 !== 0){

this.props.jia(value*1)

}

}

//异步加

incrementAsync = ()=>{

const {value} = this.selectNumber

this.props.jiaAsync(value*1,500)

}

render() {

//console.log(‘UI组件接收到的props是’,this.props);

return (

当前求和为:{this.props.count}

<select ref={c => this.selectNumber = c}>

1 2 3

 

当前求和为奇数再加 

异步加 

)

}

}

//使用connect()()创建并暴露一个Count的容器组件

export default connect(

state => ({count:state}),

//mapDispatchToProps的一般写法

/* dispatch => ({

jia:number => dispatch(createIncrementAction(number)),

jian:number => dispatch(createDecrementAction(number)),

jiaAsync:(number,time) => dispatch(createIncrementAsyncAction(number,time)),

}) */

//mapDispatchToProps的简写

{

jia:createIncrementAction,

jian:createDecrementAction,

jiaAsync:createIncrementAsyncAction,

}

)(Count)

总结

  1. 容器组件和UI组件整合一个文件

  2. 无需自己给容器组件传递store,给< App/ >包裹一个< Provider store={store} >即可。

  3. 使用了react-redux后也不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作。

  4. mapDispatchToProps也可以简单的写成一个对象

  5. 一个组件要和redux“打交道”要经过哪几步?

①定义好UI组件 —— 不暴露

②引入connect生成一个容器组件,并暴露,写法如下:

connect(

state => ({key:value}), //映射状态

{key:xxxxxAction} //映射操作状态的方法

)(UI组件)

  1. 在UI组件中通过this.props.xxxxxxx读取和操作状态

6. 数据共享版


在这里插入图片描述

store.js

/*

该文件专门用于暴露一个store对象,整个应用只有一个store对象

*/

//引入createStore,专门用于创建redux中最为核心的store对象

import { createStore, applyMiddleware, combineReducers } from “redux”;

//引入为Count组件服务的reducer

import countReducer from “./reducers/count”;

//引入为Count组件服务的reducer

import personReducer from “./reducers/person”;

//引入redux-thunk,用于支持异步action

import thunk from “redux-thunk”;

// 汇总所有的reducer变为一个总的reducer

const allReducer = combineReducers({

he: countReducer,

rens: personReducer,

});

//暴露store

export default createStore(allReducer, applyMiddleware(thunk));

总结

  1. 定义一个Pserson组件,和Count组件通过redux共享数据。

  2. 为Person组件编写:reducer、action,配置constant常量。

  3. 重点:Person的reducer和Count的reducer要使用combineReducers进行合并,合并后的总状态是一个对象!

  4. 交给store的是总reducer。


七、使用上redux调试工具

=================================================================================

1. 安装chrome浏览器插件


Redux Dev Tools

2. 下载工具依赖包


npm install redux-devtools-extension

注意:安装完成之后一定要在store中进行配置过后才可使用

import {composeWithDevTools} from ‘redux-devtools-extension’

const store = createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))


八、纯函数和高阶函数

=============================================================================

reducer要求是一个纯函数,所以操作数组的时候,不能用push之类的方法

1. 纯函数


  1. 一类特别的函数: 只要是同样的输入(实参),必定得到同样的输出(返回)

  2. 必须遵守以下一些约束

①不得改写参数数据

②不会产生任何副作用,例如网络请求,输入和输出设备

③不能调用Date.now()或者Math.random()等不纯的方法

  1. reduxreducer函数必须是一个纯函数

2. 高阶函数


  1. 理解: 一类特别的函数

①情况1: 参数是函数

②情况2: 返回是函数

  1. 常见的高阶函数:

①定时器设置函数

②数组的forEach()/map()/filter()/reduce()/find()/bind()

③promise

④react-redux中的connect函数

  1. 作用: 能实现更加动态, 更加可扩展的功能

九、最终版

========================================================================

  • 所有变量名字要规范,尽量触发对象的简写形式。

  • reducers文件夹中,编写index.js专门用于汇总并暴露所有的reducer

在这里插入图片描述

containers/Count/index.jsx

import React, { Component } from ‘react’

//引入action

import {

increment,

decrement,

incrementAsync

} from ‘…/…/redux/actions/count’

//引入connect用于连接UI组件与redux

import {connect} from ‘react-redux’

//定义UI组件

class Count extends Component {

//加法

increment = ()=>{

const {value} = this.selectNumber

this.props.increment(value*1)

}

//减法

decrement = ()=>{

const {value} = this.selectNumber

this.props.decrement(value*1)

}

//奇数再加

incrementIfOdd = ()=>{

const {value} = this.selectNumber

if(this.props.count % 2 !== 0){

this.props.increment(value*1)

}

}

//异步加

incrementAsync = ()=>{

const {value} = this.selectNumber

this.props.incrementAsync(value*1,500)

}

render() {

//console.log(‘UI组件接收到的props是’,this.props);

return (

我是Count组件,下方组件总人数为:{this.props.renshu}

当前求和为:{this.props.count}

<select ref={c => this.selectNumber = c}>

1 2 3

 

当前求和为奇数再加 

异步加 

)

}

}

//使用connect()()创建并暴露一个Count的容器组件

export default connect(

state => ({

count:state.count,

personCount:state.persons.length

}),

{increment,decrement,incrementAsync}

)(Count)

containers/Person/index.jsx

import React, { Component } from ‘react’

import {nanoid} from ‘nanoid’

import {connect} from ‘react-redux’

import {addPerson} from ‘…/…/redux/actions/person’

class Person extends Component {

addPerson = ()=>{

const name = this.nameNode.value

const age = this.ageNode.value*1

const personObj = {id:nanoid(),name,age}

this.props.addPerson(personObj)

this.nameNode.value = ‘’

this.ageNode.value = ‘’

}

render() {

return (

我是Person组件,上方组件求和为{this.props.count}

<input ref={c=>this.nameNode = c} type=“text” placeholder=“输入名字”/>

<input ref={c=>this.ageNode = c} type=“text” placeholder=“输入年龄”/>

添加

    {

    this.props.persons.map(§=>{

    return

    • {p.name}–{p.age}
    • })

      }

      )

      }

      }

      export default connect(

      state => ({

      persons:state.persons,

      count:state.count

      }),//映射状态

      {addPerson}//映射操作状态的方法

      )(Person)

      redux/actions/count.js

      /*

      该文件专门为Count组件生成action对象

      */

      import { INCREMENT, DECREMENT } from “…/constant”;

      //同步action,就是指action的值为Object类型的一般对象

      export const increment = (data) => ({ type: INCREMENT, data });

      export const decrement = (data) => ({ type: DECREMENT, data });

      //异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。

      export const incrementAsync = (data, time) => {

      return (dispatch) => {

      setTimeout(() => {

      dispatch(increment(data));

      }, time);

      };

      };

      redux/action/person.js

      import { ADD_PERSON } from “…/constant”;

      //创建增加一个人的action动作对象

      export const addPerson = (personObj) => ({ type: ADD_PERSON, data: personObj });

      redux/reducers/count.js

      /*

      1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数

      2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)

      */

      import { INCREMENT, DECREMENT } from “…/constant”;

      const initState = 0; //初始化状态

      export default function countReducer(preState = initState, action) {

      // console.log(‘countReducer@#@#@#’);

      //从action对象中获取:type、data

      const { type, data } = action;

      //根据type决定如何加工数据

      switch (type) {

      case INCREMENT: //如果是加

      return preState + data;

      case DECREMENT: //若果是减

      return preState - data;

      default:

      return preState;

      }

      }

      redux/reducers/person.js

      import { ADD_PERSON } from “…/constant”;

      //初始化人的列表

      const initState = [{ id: “001”, name: “tom”, age: 18 }];

      export default function personReducer(preState = initState, action) {

      const { type, data } = action;

      switch (type) {

      case ADD_PERSON: //若是添加一个人

      //preState.unshift(data) //此处不可以这样写,这样会导致preState被改写了,personReducer就不是纯函数了。

      return [data, …preState];

      default:

      return preState;

      }

      }

      redux/reducers/index.js

      /*

      该文件用于汇总所有的reducer为一个总的reducer

      */

      //引入combineReducers,用于汇总多个reducer

      import { combineReducers } from “redux”;

      //引入为Count组件服务的reducer

      import count from “./count”;

      //引入为Person组件服务的reducer

      import persons from “./person”;

      //汇总所有的reducer变为一个总的reducer

      export default combineReducers({

      count,

      persons,

      });

      redux/constant.js

      /*

      该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错

      */

      export const INCREMENT = “increment”;

      export const DECREMENT = “decrement”;

      export const ADD_PERSON = “add_person”;

      redux/store.js

      /*

      该文件专门用于暴露一个store对象,整个应用只有一个store对象

      */

      //引入createStore,专门用于创建redux中最为核心的store对象

      import { createStore, applyMiddleware } from “redux”;

      //引入汇总之后的reducer

      import reducer from “./reducers”;

      //引入redux-thunk,用于支持异步action

      import thunk from “redux-thunk”;

      //引入redux-devtools-extension

      import { composeWithDevTools } from “redux-devtools-extension”;

      //暴露store

      export default createStore(

      reducer,

      composeWithDevTools(applyMiddleware(thunk))

      );

      更多面试题

      **《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等

      开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

      ducers/index.js

      /*

      该文件用于汇总所有的reducer为一个总的reducer

      */

      //引入combineReducers,用于汇总多个reducer

      import { combineReducers } from “redux”;

      //引入为Count组件服务的reducer

      import count from “./count”;

      //引入为Person组件服务的reducer

      import persons from “./person”;

      //汇总所有的reducer变为一个总的reducer

      export default combineReducers({

      count,

      persons,

      });

      redux/constant.js

      /*

      该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错

      */

      export const INCREMENT = “increment”;

      export const DECREMENT = “decrement”;

      export const ADD_PERSON = “add_person”;

      redux/store.js

      /*

      该文件专门用于暴露一个store对象,整个应用只有一个store对象

      */

      //引入createStore,专门用于创建redux中最为核心的store对象

      import { createStore, applyMiddleware } from “redux”;

      //引入汇总之后的reducer

      import reducer from “./reducers”;

      //引入redux-thunk,用于支持异步action

      import thunk from “redux-thunk”;

      //引入redux-devtools-extension

      import { composeWithDevTools } from “redux-devtools-extension”;

      //暴露store

      export default createStore(

      reducer,

      composeWithDevTools(applyMiddleware(thunk))

      );

      更多面试题

      **《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等

      开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

      [外链图片转存中…(img-QDZDrOgf-1715795366223)]

    • 22
      点赞
    • 24
      收藏
      觉得还不错? 一键收藏
    • 0
      评论
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值