一、生命周期
1,初始化的执行顺序,初始生命周期执行过程详解
react 本质上是一个 JavaScript 的库,是创建UI接口的视图层框架
(图一)
如图一所示,假如蓝色组件需要和灰色组件通信,只使用 react 视图层框架,就需要调用父组件函数的形式通信,逐层往父级通信
但对于大型应用来说,这样实现基本不太可能,过多的组件会造成维护困难,那应该怎么做呢?
这个时候就应该在 react 视图层框架上配套一个数据层框架 — Redux ,结合应用
redux 要求我们把数据都放在 store 公共存储空间,当绿色组件想要去传递数据时,只需要改变 store 里边对应的数据,灰色区域会自动感知到 store 有变化,就会重新去 store 取数据,从而灰色组件就能得到新的数据
这样的操作流程对于深层次的组件是非常适用的,组件与组件之间的数据传递会变得非常简单
组件改变,修改数据,其他组件再来取值。这就是 Redux 的基础设计理念
使用 Redux-thunk 中间件进行ajax请求发送
如果我们把这种异步的请求,或者把一些非常复杂的逻辑都放在组件里进行实现时,这个组件会显得过于臃肿
所以遇到这种异步请求或者非常复杂的逻辑,最好是把它移出到其他页面进行统一的处理,
这个时候 Redux-thunk
这个中间件就显得至关重要了,它可以将这些异步请求或者是复杂的逻辑放到 action 去处理,那如何使用 Redux-thunk
这个中间件呢?
打开github,搜索 Redux-thunk ,star最多的项目,就是Redux-thunk
按照它的使用说明进行如下操作
import { createStore, applyMiddleware } from 'redux'
import reducer from './reducer'
import thunk from 'redux-thunk' const store = createStore(
reducer,
applyMiddleware(thunk) // applyMiddleware可以使用中间件模块
) export default store
需要注意的是:
中间件是通过创建 redux 的 store 时使用的,所以这个中间件是指的 redux 中间件,而不是 react 中间件
原则上 action 返回的是一个对象,但当我们使用
redux-thunk
中间件后, action 就可以返回一个函数了,继而可以在函数里边进行异步操作,也就可以把 TodoList 获取数据的请求放入这个函数中了
接着操作,在 actionCreator 中创建 action 的函数,然后数据传给 store
那问题来了,怎么传呢?本质还是调用 dipatch 方法,但是现在 actionCreactor 这个文件里并没有 store 这个数据仓库,也就没有 dispatch 这个方法,怎么办呢?
实际上,当我们创建一个内容是函数的 action 时,返回的函数就会自动接收到 store.dispatch
这个方法,所以只要在返回的函数里调用 dispatch ,然后派发 action 就好了, store 判断接收的 action 是一个对象,就会接收并发送给 reducer 进行数据更新操作
export const getTodoList = () => {
return (dispatch) => {
axios.get('/list.json').then((res) => {
const data = res.data
const action = initListAction(data)
dispatch(action)
})
}
}
在 TodoList 组件中引用这个创建内容是函数的 action
componentDidMount() {
const action = getTodoList ();
store.dispatch(action);
}
有的小伙伴可能会有疑问,就一个ajax请求,放在 componentDidMount 会有影响吗?
考虑到后期代码量的增加,如果把异步函数放在组件的生命周期里,这个生命周期函数会变得越来越复杂,组件就会变得越来越大
所以,还是应该把这种复杂的业务逻辑或者异步函数拆分到一个地方进行管理,现在借助 redux-thunk
,就可以放在 actionCreactor 里边集中管理,除此之外,在做自动化测试的时候,测试 actionCreactor 这个方法,也会比测组件的生命周期函数要简单的多
到底什么是 Redux 中间件
view 到 redux 的过程中会派发一个 action , action 通过 Store 的 dispatch 方法,会派发给 store , store接收到 action ,再连同之前的 state 一起传给 reducer , reducer 返回一个新的数据给 store , store 就可以去改变自己的 state ,组件接收到新的 state 就可以重新渲染页面了
redux的中间件在这个流程里边,指的是谁和谁之间呢?指的是 action 和 store 中间
action 通过 dispatch 方法被传递给 store ,那么 action 和 store 之间是不是就是 dispatch 这个方法呢?实际上,我们说的中间件就是指的 dispatch 方法的一个封装,或者是对 dispatch 方法的一个升级
最原始的 dispatch 方法,接收到对象 action 后会传递给 store ,这就是没有中间件的情况
对 dispatch 方法做了一个升级后,也就是使用中间件时,再调用 dispatch 方法,如何给 dispatch 传递的仍然是个对象, dispatch 就会把这个对象传给 store ,跟之前的方法没有任何区别;但是假如传的是个函数,就不会直接传递给 store 了,会让这个函数先执行,然后执行完之后需要调用 store ,这个函数再去调用 store
dispatch方法会根据参数的不同,执行不同的事情,如果参数是对象,就直接传给store,如果是函数,那就把函数执行结束
所以,redux的中间件原理很简单,就是对 store 的 dispatch 方法做一个升级,既可以接收对象,又可以接收函数了,那是用什么方法进行的升级的呢?就是用 redux-thunk
这个中间件进行升级的
当然,redux的中间件还有 redux-log
,原理就是在派发 action 给 store 之前先 console.log 出来;还有 redux-saga
,接下来需要讲解的
React-Redux 的使用
目前我们已经了解了 react 和 redux ,那 React-Redux
是什么呢?它是一个第三方的模块,可以在 react 中非常方便是使用 redux
重新来编写 todolist 功能,在 index 文件中引入 react-redux
import React from 'react'
import ReactDOM from 'react-dom'
import TodoList from './TodoList'
import { Provider } from 'react-redux'
import store from './store' const App = (
<Provider store={store}>
<TodoList />
</Provider>
) ReactDOM.render(App, document.getElementById('root'))
Provider
实质是一个组件,是一个提供器,是 react-redux
的一个核心API,连接着 store , Provider
里边所有的组件,都有能力获取到 store 里边的内容
react-redux
的另一个核心方法叫做 connect ,接收三个参数,最后一个参数是连接的组件,前面两个是连接的规则
之前说 Provider 组件连接了 store , Provider 内部的组件有能力获取到 store ,是怎样获取的呢?就是通过 connect 这个方法获取到里面的数据的
意思是让 TodoList 组件和 store 进行连接,所以 connect 方法的意思是做连接,在做连接时需要有一定的方式和规则,就是用 mapStateToProps
方法来做关联,翻译为中文就是把 store 里的数据 inputValue 映射到组件 inputValue 这个位置,为组件的 props 的数据
import React, { Component } from 'react'
import { connect } from 'react-redux' class TodoList extends Component {
render () {
return (
<div>
<div>
<input value={this.props.inputValue} />
<button>提交</button>
</div>
<ul>
<li>Dell</li>
</ul>
</div>
)
}
} const mapStateToProps = (state) => {
return {
inputValue: state.inputValue, }
} export default connect(mapStateToProps, null)(TodoList)
如果需要对 store 的数据做修改,dispatch 是指的 store.dispatch
,可以通过 mapDispatchToProps
方法把 store.dispatch
挂载到props上,为什么呢?
因为想要改变 store 里的内容,就要调用 dispatch 方法, dispatch 方法被映射到了 props 上,所以就可以通过 this.props.dispatch 方法去调用了
import React, { Component } from 'react'
import { connect } from 'react-redux' class TodoList extends Component {
render () {
return (
<div>
<div>
<input value={this.props.inputValue} onChange={this.props.handleInputChange} />
<button>提交</button>
</div>
<ul>
<li>Dell</li>
</ul>
</div>
)
}
} const mapStateToProps = (state) => {
return {
inputValue: state.inputValue
}
}
const mapDispatchToProps = (dispatch) => {
return {
handleInputChange(e) {
const action = {
type: 'change_input_value',
value: e.target.value
}
dispatch(action)
}
}
} export default connect(mapStateToProps, mapDispatchToProps)(TodoList)
现在在 input 里输入值的功能就完成了,那todolist的增加功能怎么实现呢?
(TodoList.js)
<button onClick={this.props.handleClick}>提交</button> const mapDispatchToProps = (dispatch) => {
return {
handleInputChange(e) {
const action = {
type: 'change_input_value',
value: e.target.value
}
dispatch(action)
}, handleClick() {
const action = {
type: 'add_todo_item'
}
dispatch(action)
}
}
}
(reducer.js)
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_todo_item') {
const newState = JSON.parse(JSON.stringify(state))
newState.list.push(newState.inputValue)
newState.inputValue = ''
return newState
}
return state
}
点击这个 button 的时候,会执行 handleClick 这个方法,这个方法会把创建出来的 action 传给 store ,再传给 reducer, reducer 接收到这个 action 之后,去处理数据,把新的数据返回出去,新的数据就包含列表项的新内容了,数据发生了改变,todolist 组件恰好又通过 connect 跟数据做了连接,所以这块是个自动的流程,数据一旦发生改变,这个组件自动就会跟的变
以前还需要 store.subscribe
做订阅,现在连订阅都可以不用了,页面自动跟随数据发生变化
这样写就实现了增加 item 的功能,
比如 item 的删除操作, action 要通过 actionCreator
来创建,同时,还需要把 action 的 type 字符串放在 actionType
里面进行管理等等
创建 TodoList 这个组件,正常来说都是 export default TodoList
,把这个组件导出出去,但是�现在 export defalut 出的东西是通过 connect 方法执行的结果,connect 方法做了一件什么事呢?
它把这些映射关系和业务逻辑集成到了 TodoList 这个 UI 组件之中,所以 connect 方法可以这样理解,TodoList 是一个 UI 组件,当你用 connect 把这个 UI 组件和一些数据和逻辑相结合时,返回的内容实际就是一个容器组件了,容器组件可以理解成数据处理包括派发这样的业务逻辑,对 UI 组件进行包装,去调用这些UI组件,数据和方法都准备好了
有的小伙伴可能在网上看到过这样的描述,react-redux
组件既有 UI 组件,又有容器组件。UI 组件就是 TodoList 这个东西,而容器组件就是 connect 方法返回的结果,或者说 connect 方法执行生成的内容
所以 export default
导出的内容就是 connect
方法执行的结果,是一个容器组件
react生命周期,中间件、性能优化、数据传递、mixin的使用的更多相关文章
-
【React】393 深入了解React 渲染原理及性能优化
如今的前端,框架横行,出去面试问到框架是常有的事. 我比较常用React, 这里就写了一篇 React 基础原理的内容, 面试基本上也就问这些, 分享给大家. React 是什么 React是一个专注 ...
-
【React学习笔记】React生命周期梳理(16.X前后两种)
React生命周期 「16版本以前的:」 生命周期流程图 组件从生成到被挂在到页面上的一系列过程 根据流程图打印的执行顺序图: 流程讲解: 初始化流程 start 开始创建组件 在这个周期中做的事情 ...
-
React 生命周期
前言 学习React,生命周期很重要,我们了解完生命周期的各个组件,对写高性能组件会有很大的帮助. Ract生命周期 React 生命周期分为三种状态 1. 初始化 2.更新 3.销毁 初始化 1.g ...
-
React生命周期简单详细理解
前言 学习React,生命周期很重要,我们了解完生命周期的各个组件,对写高性能组件会有很大的帮助. Ract生命周期 React 生命周期分为三种状态 1. 初始化 2.更新 3.销毁 初始化 1.g ...
-
React生命周期执行顺序详解
文章内容转载于https://www.cnblogs.com/faith3/p/9216165.html 一.组件生命周期的执行次数是什么样子的??? 只执行一次: constructor.compo ...
-
vue生命周期和react生命周期对比
一 vue的生命周期如下图所示(很清晰)初始化.编译.更新.销毁 二 vue生命周期的栗子 注意触发vue的created事件以后,this便指向vue实例,这点很重要 <!DOCTYPE ht ...
-
前端005/React生命周期
ES6中React生命周期 一.React生命周期 React生命周期主要包括三个阶段:初始化阶段.运行中阶段和销毁阶段. 在React不同的生命周期里,会依次触发不同的钩子函数. 二.React的生 ...
-
React生命周期
在react生命周期中,分2段执行,一个挂载的生命周期,一个是组件发生了数据变动,或者事件触发而引发的更新生命周期. 注:react生命周期很重要,对于很多组件场景的应用发挥重要作用,而且不熟悉生命周 ...
-
22.1 、react生命周期(一)
在每个react组件中都有以下几个生命周期方法~我们需要在不同阶段进行讨论 组件生命周期概述 1.初始化 在组件初始化阶段会执行 constructor static getDerivedStateF ...
-
react复习总结(2)--react生命周期和组件通信
这是react项目复习总结第二讲, 第一讲:https://www.cnblogs.com/wuhairui/p/10367620.html 首先我们来学习下react的生命周期(钩子)函数. 什么是 ...
随机推荐
-
查看Sql Server所有表占用的空间大小
2010-01-26 sp_spaceused可以查看某个表占用的空间,但不能一次查看所有的表.今天研究了一下这个sp,写了下面这个查询: --刷新系统数据dbcc updateusage(0) wi ...
-
Java中static关键字的详解
static关键字可以修饰方法和成员变量(不可以修饰局部变量,但是可以修饰内部类). static关键字方便在没有创建对象的情况下来进行调用(方法/变量). 很显然,被static关键字修饰的方法或者 ...
-
MySQL 高性能优化实战总结
1 前言 2 优化的哲学 3 优化思路 3.1 优化什么 3.2 优化的范围有哪些 3.3 优化维度 4 优化工具有啥? 4.1 数据库层面 4.2 数据库层面问题解决思路 4.3 系统层面 4.4 ...
-
使用指针来实现变长数组(VLA)
实现代码: #include <cstdio> #include <cstdlib> void usePtoImplementVLA(int SIZE) { scanf(&qu ...
-
进程篇:wait & waitpid
#include <sys/types.h> /* 提供类型pid_t的定义 */ #include <sys/wait.h> pid_t wait(int *status) ...
-
vim 常用命令(一)特殊删除
dd 可以删除光标当前行: ndd n代表行数,3dd,删除从当前光标往下3行: di 删除在指定符号内的内容,如 空号,引号内: dt 删除当前光标到指定符号的内容
-
pager-taglib分页处理的使用
pager-taglib是java中一个用于分页的小的框架.下面简单介绍一下它的具体使用. 一.环境的搭建: 将pager-taglib-2.0.war包拷贝到Tomcat的webapps下.启动To ...
-
Leetcode590. N-ary Tree Postorder Traversal
590. N-ary Tree Postorder Traversal 自己没写出来 优秀代码: """ # Definition for a Node. cla ...
-
CentOS6、7优化脚本完美版
#!/bin/bash SysVer=`cat /etc/redhat-release | awk -F'release' '{print $2}' | awk -F'[ .]+' '{print $ ...
-
window端口号被占用解决
1. 找到占用该端口的pid netstat -ano|findstr "端口号" 2. 强制关闭该占用该端口的进程 // 关闭 taskkill -pid 刚才查的pid // ...