在jsx中不能使用class定义类名 因为class在js中是用来定义类的 定义类名的时候用className
label中的for必须写成htmlFor
ReactDOM.render:
参数1:需要渲染的dom元素或者组件
参数2:需要将渲染好的元素挂载在哪个挂载点身上
参数3:回调 成功的回调
React中如何创建一个组件
通过class类的方式来创建一个组件
class 组件名称 extends React.Component
注意:这个组件中必须要写一个render函数 函数中必须返回一个jsx语法
插槽作用:
插槽即:ReactDOM.createPortal(child, container) ,由ReactDom提供的接口。 可以实现将子节点渲染到父组件DOM层次结构之外的DOM节点。
第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或 片段(fragment)。第二个参数(container)则是一个 DOM 元素。
应用场景:
对于 portal 的一个典型用例是当父组件有 overflow: hidden 或 z-index 样式,但你需要子组件能够在视觉上 “跳出(break out)” 其容器。例如,对话框、hovercards以及提示框。所以一般react组件里的模态框,就是这样实现的~
React.Component:
是所有组件的父类。通过继承父类来创建组件。这个类中会包含很多方法(例如生命周期)
render:
是一个生命周期,用来渲染jsx语法
constructor:
是一个生命周期函数,用来存放当前组件所需要的一些状态 状态存放在this.state中这个类中的this指向会指向当前这个组件
注意:当书写了constructor后必须要写super否则this的指向会发生错误
React中的事件绑定优化
1、不需要传值的情况下去
在constructor中定义函数 例如:this.handleClick = this.handleClick.bind(this)
在render函数中使用定义好的函数 <button onClick={this.handleClick}>点击</button>
2、需要传值的情况下
<button onClick={this.handleClick.bind(this,需要传递的值)}>点击</button>
3、不推荐使用
<button onClick={()=>{
this.setState({
message:123
})
}}>点击</button>
setState:
当需要修改this.state中的数据的时候我们需要调用this.setState;
this.setState这个方法是异步的
书写方式2种
1、
this.setState({
key:val
})
2、this.setState((state)=>{
let str = (state.message + "").split("").reverse().join("")
return {
message:str
}
})
参数1:是一个对象 || 是一个函数 这个函数必须返回一个对象
参数2:回调 作用:1、验证数据是否修改成功 2、获取数据更新后最新的DOM结构
setState 只在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout 中都是同步的。
setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。
setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新。
forceUpdate
这个方法用来做强制刷新
注意 :react 中一切皆为组件
react生命周期
constructor():(1次)
进行组件的初始化,且必须要写super函数,否则this指向会发生错误
可以用this.state来定义当前组件所需要的一些状态
当前生命周期特殊情况下接收不到props 的数据,如果想要接收到数据,需要在super和 constructor中传递props这个参数
componentWillMount():(1次) 挂载前 (17.0版本废除了)
当前生命周期可以接收到props传递过来的数据,可以将外部数据转化为内部数据
注意尽量不要使用this.state 因为当前生命周期执行完毕以后,下一个生命周期就是render函数 在当前生命周期中我们可以对this.state中的数据做初始化的最后一次修改
render():(多次) 渲染
作用是将数据与虚拟DOM进行结合,进行数据渲染,并且在第一次执行完会将渲染结果在内存中保留一份
第二次执行的时候会与内存中的虚拟DOM进行对比 这种方式叫做diff算法(新旧两个虚拟DOM的对比就是diff算法)
key值的作用:
componentDidMount():挂载后(1次)
当前生命周期可以获取到真实的DOM结构,一般情况下我们可以在当前生命周期中进行Ajax的请求||进行方法的实例化
如何获取到真实的dom结构
1、this.refs 属性
2、<元素 ref={(形参)=>this.属性 = 形参}></元素>
这里面的形参代表的是当前的DOM元素 使用: this.属性
componentWillReceiveProps():(多次) (废除)
当props的数据发生改变的时候当前生命周期就会执行,当前是生命周期中有一个参数就是新的props
在当前生命周期中可以用来检测外部数据的更新
shouldComponentUpdate()(多次)
1、当state||props中的数据发生改变的时候会执行当前生命周期,当前生命周期必须要返回一个布尔值, 当返回true的时候会执行
下面的生命周期,如果返回false则下面的生命周期不会执行(render函数不会执行),
2、当前生命周期中会有2(3)个参数 一个是新的props 一个是新的state。我们可以通过新的props ||state 与 旧的props和state进行
对比,来进行性能优化
3、当前生命周期决定的是render函数是否渲染,而不是数据是否更新,哪怕返回值是false 数据其实也会进行更新的
4、千万不要在这里面执行this.setState否则会造成死循环
componentWillUpdate:(多次) (废除)
当前生命周期可以用来做更新数据的最后一次修改
当前生命周期中有2个参数一个是新的props 一个是新的state 我们可以通过新的props || 新的state来做数据最后的一次更改
componentDidUpdate():(多次)
当前生命周期可以获取到数据更新后最新的DOM结构
当前生命周期数据与模板已经进行相结合,生成最新的DOM结构了
注意如果我们在当前生命周期中做一些实例化的时候 一定要加判断
当前生命周期也有2个参数 一个是旧的props 一个是旧的state
componentWillUnmont():卸载(一次)
当前生命周期的作用来做事件的解绑 / 事件移除 等操作
面试题
面试题
1、组件加载的时候第一次执行的生命周期有哪些?
constructor
componentWillMount
render
componentDidMount
2、哪些生命周期会执行一次?
constructor
componentWillMount
componentDidMount
componentWillUnmount
3、哪些生命周期会执行多次
render
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate
4、当this.setState执行完毕以后会执行哪些生命周期
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
5、当this.props发生改变的时候会执行哪些生命周期
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
6、当组件的key值发生改变的时候会执行哪些生命周期
componentWillUnmount
constructor
componentWillMount
render
componentDidMount
context 跨组件传值
1、通过react.createContext创建全局的GlobalContext来创建 一个 context
2、在根组件中通过GlobalContext.Provider创建一个全局的生产者
3、GlobalContext.provide中有一个属性value用来定义子组件所需要用到的状态值
4、在子组件中通过GlobalContext.Consumer来创建消费者。GlobalContext.Consumer内部必须通过一个函数来接收生产者的状态,且这个函数必须返回一个jsx语法。
路由
1、安装路由 cnpm install react-router-dom -S
2、引入react-router-dom 选择引入形式
1、 HashRouter : 路由的根组件 也是路由的一种形式 (hash路由) 带#号
所有的路由的配置下项都必须在路由的根组件内部
2、BrowerRouter : 路由的根组件 也是路由的一种 (history路由) 不带#号
3、引入Router Router 是路由渲染的方式
常用的属性:
path:路径
component:需要渲染的组件 值是组件的名称
render: 需要渲染的组件 值是组件
exact:完全匹配
4、路由跳转的方式 a标签 link NavLink 编程式导航
Link && NavLink区别?
前者没有选中的标识 后者会有选中的标识
场景:前者非TabBar 后者TabBar
属性:
activeClassName: 设置选中后的类名
activeStyle:设置选中后的状态
5、Redirect:路由重定向
属性:
from:从哪里来
to:到哪里去
exact:完全匹配
最外层加上Switch
6、Switch
Switch 是一个组件 作用是只匹配一个路由
7、路由的嵌套
1、通过render的方式进行嵌套
2、将嵌套的内容放到Switch的外面
8、路由的传参
动态路由:(使用最多)
1、在定义路由的时候/:属性的方式来定义传递的属性
2、在路由跳转的时候传递需要传递的数据
3、接收:this.props.match.params
Query传值:
1、在路由跳转的时候通过地址拼接的方式进行数据的传递(类似于get传值的方式)
2、接收的时候通过this.props.loacltion.search 进行接收(注意需要url模块的解析)
const url = require("url");
对象传值:
1、在路由跳转的时候通过对象的方式进行路由跳转
<li key={index}><Link to={{pathname:"/detail",query:{id:item.id,name:item.name}}}>{item.name}</Link></li>
2、2、接收的时候通过this.props.location.query进行接收
(注意:刷新浏览器的时候数据会丢失 慎用)
9、编程式导航:
this.props.history.goBack()
this.props.history.push()
this.props.history.goForward()
this.props.history.replace()
例如:
this.props.history.push({pathname:"/detail",query:{id:item.id,name:item.nam}})
render 与 component 的区别?
render:
1、render可以渲染组件,以及标签
2、render渲染方式可以进行组件传参
3、render的渲染方式可以进行逻辑判断
4、render的渲染方式可以进行路由嵌套
component:
1、只能渲染组件,因为component的值是组件的名称,而不是组件标签
2、component的值因为组建的名称不能传递,也不能做逻辑判断 以及路由嵌套
3、只要通过component渲染的组件,身上会有三个属性 history location match (优点)
函数组件与类组件的区别?
函数组件:
优点: 运行速度快 没有状态 也没有生命周期 只会有view层 类似于UI组件
类组件:
优点:可以存储组件所需要的状态 以及继承过来的一些生命周期的调用
Hooks:
让函数组件拥有类组件的一些功能(存储状态 生命周期)
useState : 函数 书写多个的
存储当前组件所需要的一些状态
参数:所需要的状态值
返回值:数组
1、当前状态的key值
2、修改当前状态的函数
hooks中的生命周期 : componentDidMount componentDidUpdate componentWillUnmount (模拟出来的)
useEffect:模拟类组件的一些生命周期
参数1:函数
参数2:依赖值
如果第二个参数不写的情况下,参数1可以模拟 componentDidMount componentDidUpdate
如果第二个参数书写的情况下,且第二个参数是一个不变值得情况下 第一个参数只能模拟 componentDidMount
如果需要模拟componentWillUnmount 则只需要第一个参数中return 一个函数 在这个函数中做一些卸载组件的操作(事件的移除 解绑等)
flux: 公共状态管理
安装:cnpm install flux -S
1、View
2、Action
3、Dispatcher
4、Store
流程:
1、用户访问 View
2、View 发出用户的 Action
3、Dispatcher 收到 Action,要求 Store 进行相应的更新
4、Store 更新后,发出一个"change"事件
5、View 收到"change"事件后,更新页面
缺点:
1、管理多个store
2、频繁引入store
3、UI组件 容器组件的拆分
4、事件订阅每次都需要绑定
redux :公共状态管理
安装 cnpm install redux -S
数据传递的流程:
当组件需要修改数据的时候必须创建一个action,然后通过store.dispatch将action传递给store,store接收到action后将action传递给reducer,reducer接收到action后将action.type相比较,然后进行数据的修改,(要注意state只允许读不允许修改,深拷贝)数据修改完后返回一个新的state。最后通过store.subscribe通知所有组件数据更新。
深拷贝的问题:
const newState = JSON.parse(JSON.stringify(state));
会深度拷贝每一个节点 这个过程是特别耗费性能的
持久化数据结构 immutable 一旦被创建就不会再被更改的数据
原理:结构共享
特点:只要数据被修改就会返回一个新的immutable对象
fetch:
fetch是 window下面的一个方法,脱离了XHR 是ES的规范 兼容性不太好 fetch基于promise的API
1、安装
cnpm install whatwg-fetch -S
2、GET请求 默认就是get请求
fetch(url+?key=val,{
headers:请求头
method:请求的方式
})
3、post
fetch(url,{
headers:请求头
method:请求的方式
body:post传递参数的属性
})
特点:
不管post请求还是get请求,当请求成功后第一个.then中是一个未处理的结果集
第二个.then中才是你想要的数据。fetch默认是不会携带cookie的,如果需要携带cookie则设置
credentials:"include"
fetch(url)
.then((res)=>{结果集的处理})
.then((data)=>{
console.log(data);
})
结果集的处理:你想要的数据格式是哪种格式 text json blob formData
2、GET请求 默认即使get请求
fetch(url+?key=val,{
headers:请求头,
method:请求方式
})
3、POST请求
fetch(url,{
headers:请求头,
method:请求方式
body:post传递参数的属性
})
特点:不论是post还是get请求,当请求成功后的第一个.then中的是一个未处理的结果集
第二个.then中才是你想要的数据。fetch默认不会携带cookie
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:
从浏览器中创建 XMLHttpRequest
从 node.js 发出 http 请求
支持 Promise API
拦截请求和响应
转换请求和响应数据
自动转换JSON数据
客户端支持防止CSRF/XSRF
fetch:
符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里
更加底层,提供的API丰富(request, response)
脱离了XHR,是ES规范里新的实现方式
1)fetchtch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
2)fetch默认不会带cookie,需要添加配置项
3)fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了量的浪费
4)fetch没有办法原生监测请求的进度,而XHR可以
purComponent:
1、 pureComponent表示一个纯组件,可以用来优化react程序。减少render函数渲染的次数。提高性能
pureComponent进行的是浅比较,也就是说如果是引用数据类型的数据,只会比较不是同一个地址,而不会比较这个地址里面的数据是否一致
浅比较会忽略属性和或状态突变情况,其实也就是数据引用指针没有变化,而数据发生改变的时候render是不会执行的。如果我们需要重新渲染那么就需要重新开辟空间引用数据
好处:
当组件更新时,如果组件的props或者state都没有改变,render函数就不会触发。省去虚拟DOM的生成和对比过程,达到提升性能的目的。具体原因是因为react自动帮我们做了一层浅比较
2、使用场景
1、PureComponent一般会用在一些纯展示组件上。切结props和state不能使用同一个引用
2、在通过PureComponent进行组件的创建的时候不能够在写shouldComponentUpdate. 否则会引发警告
脚手架 cnpm install create-react-app -g
create-react-app react-demo 后面是文件名
Immutable
实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。 Immutable 则提供了简洁高效的判断数据是否变化的方法,只需 === 和 is 比较就能知道是否需要执行 render(),而这个操作几乎 0 成本,所以可以极大提高性能。
一、immutable简介
Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗。
在js中,引用类型的数据,优点在于频繁的操作数据都是在原对象的基础上修改,不会创建新对象,从而可以有效的利用内存,不会浪费内存,这种特性称为mutable(可变),但恰恰它的优点也是它的缺点,太过于灵活多变在复杂数据的场景下也造成了它的不可控性,假设一个对象在多处用到,在某一处不小心修改了数据,其他地方很难预见到数据是如何改变的,针对这种问题的解决方法,一般就像刚才的例子,会想复制一个新对象,再在新对象上做修改,这无疑会造成更多的性能问题以及内存浪费。
为了解决这种问题,出现了immutable对象,每次修改immutable对象都会创建一个新的不可变对象,而老的对象不会改变
二、React中如何减少render函数渲染的次数
在React中我们知道当this.state 、this.props发生改变的时候render函数就会执行,但有些时候this.state、this.props没有发生改变的时候render函数也会执行(具体请自行了解相关案例,如需详解请留言)。那么我们如何来减少render函数渲染的次数来提高React的性能优化?接下来我们可以封装一个BaseComponent来减少React中render函数渲染的次数
i
注意:本文所进行优化的数据必须统一都是immutable数据,哪怕是this.props
001、react中如何创建一个组件
方案一:ES6写法
class
组件名称
extends
Component
{ }
方案二:ES5写法
var App = React.createClass({})
002、render函数什么时候会执行?
当this.state 或者this.props发生改变的时候render函数就会执行
003、react中如何对state中的数据进行修改?setState为什么是一个异步的
修改数据通过this.setState(参数1,参数2)this.setState是一个异步函数
参数1: 是需要修改的数据是一个对象,
参数2: 是一个回调函数,可以用来验证数据是否修改成功,同时可以获取到数据更新后的DOM结构 等同于componentDidMount
this.setState中的第一个参数除了可以写成一个对象以外,还可以写成一个函数,函数中第一个值为prevState 第二个值为prePprops
this.setState((prevState,prop)=>({}))
为什么setState是一个异步的?当批量执行state的时候可以让DOM渲染的更快,也就是说多个setstate在执行的过程中还需要被合并
004、react中如何定义自定义属性,以及限制外部数据的类型
1、自定义属性
组件名称.defaultProps={
key:val
}
2、限制外部数据的类型
a、引入propTypes第三方模块
b、类型限制
组件名称.propTypes={
key:propTypes.类型
}
005、react路由常用的一些组件配置项有哪些?
BrowserRouter
HashRouter
withRouter
Route
Link
NavLink
Switch
Redirect
BrowserRouter 和 HashRouter是路由的根组件,跟组件下面只能有一个子元素
Route是路由路径所对应的组件
Link和 NavLink是进行路由的跳转。区别是当选中标签的时候NavLink会加上一个class
Swicth:被Switch包裹的Route渲染的时候只会渲染一个路径,建意:子页面不要放在Switch里面,主页面放在Switch里面
Redirect:设置路由的重定向
006、reatc路由中Route渲染组件的方法有哪几种?区别是什么?
渲染方式有2种
1、<Route path="/home"component={组件名称}></Route>
通过component进行组件的渲染,这种方式的优点在于可以直接在组件的内部接受到history、location、match,缺点在于如果需要组件传参,或者渲染jsx语法的时候无法使用
2、<Route path="/home" render={()=>{return<Home/>}}></Route>
通过render进行渲染组件,优点在于可以进行组件传参,还可以渲染非组件的标签,缺点在于如果需要使用 histroy location match的话需要在函数中传递过去
007、如何控制路由的路径完全匹配
给NavLink 或者 Route设置 exact属性
008、react中路由传递参数的方法有哪些?
方案一:
//通过params进行传值
<Router path="/one/:id" render={(history)=>{
return <One history={history}/>
}}>
// html跳转:
<NavLikn to={"/one/"+1}>one<NavLink>
// js跳转:
this.props.history.push('/one/'+'1')
// 接收值:
在组件内部通过
constructor
参数进行接受
constructor({history,location,match}){
super();
/进行接受
console.log(match.params)}
// 方案二:
// 通过query
<Router path="/one" render={(history)=>{
return <One history={history}/>
}}>
// html跳转:
<NavLikn to={{pathname:"/one",query:{data:1}}}>one<NavLink>
// js跳转:
this.props.history.push({ pathname :'/one',query : { data:1} })
// 获取值
this.props.location.query.data
注意:如果通过render进行渲染的时候需要在回调中将history的值传递过去.如果是component进行渲染的话,我们只需要通过
this.props进行接受即可。
009、react中的编程式导航方法有哪些?
this.props.history.push("需要跳转的路径");跳转路径
this.props.history.back();返回
this.props.history.forward():前进
this.props.history.replace():替换
010、react中的生命周期有哪些?
(1)、组件创建的过程
constructor
componentWillMount
render
componentDidMount
(2)当props中的数据发生改变后会执行哪些生命周期函数
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
(3)组件销毁的时候
componentWillUnmount
011、reatc中如何强制更新DOM
this.foreUpdate()
012、谈谈你对react生命周期中shouldComponentUpdate的理解
shouldComponentUpdate是react性能优化非常重要的一环。
组件接受新的
state或者props时调用,我们可以设置在此对比前后两个props和state是否相同,如果相同则返回false阻止更新,因为相同的属性状态一定会生成相同的dom树,这样就不需要创造新的dom树和旧dom树进行diff算法对比,节省大量性能,尤其是在dom结构复杂的时候
013、谈谈你对虚拟DOM的理解,以及好处?
虚拟DOM:虚拟DOM其实就是真实的js对象虚拟DOM提高了react的性能,每次数据更新后都会重新计算上虚拟DOM,并和上一次的虚拟DOM进行对比,对方法变化的部分进行批量更新。react中也提供了
shouldComponentUpdate生命周期的回调,来减少数据变化后不必要的虚拟DOM对比过程。保证性能
014、谈谈你对flux的理解
利用单项数据流的方式来组合react的视图组件,它是一种模式,而不是一种框架
简单来说flux可以帮我们解决非父子组件之间传值
flux数据传递流程
https://www.cnblogs.com/nanianqiming/p/9870194.html
015、react17废除的生命周期函数,与新增的生命周期函数
由于未来采用异步渲染机制,所以即将在17版本中去掉的生命周期钩子函数
componentWillMount
componentWillRecieveProps
componentWIllUpdate
新增的生命周期
staticgetDerivedStateFromProps(nextProps, prevState){}用于替换componentWillReceiveProps,可以用来控制 props 更新 state的过程;它返回一个对象表示新的 state;如果不需要更新,返回null即可在每次渲染之前都会调用,不管初始挂载还是后面的更新都会调用,这一点 和componentWillReceiveProps不同(只有当父组件造成重新渲染时才调用) 每次都应该返回一个对象作为
getSnapshotBeforeUpdate() {}
用于替换 componentWillUpdate,该函数会在update后 DOM 更新前被调用,
用于读取最新的 DOM 数据,返回值将作为 componentDidUpdate 的第三个参
数,在最新的渲染数据提交给DOM前会立即调用,它让你在组件的数据可能要改
变之前获取他们
componendDidCatch(error, info){}
如果一个组件定义了componentDidCatch生命周期,则他将成为一个错误边
界(错误边界会捕捉渲染期间、在生命周期方法中和在它们之下整棵树的构造
函数中的错误,就像使用了trycatch,不会将错误直接抛出了,保证应用的
可用性)
016、this.setState之后react做了哪些操作
1、shouldComponentUpdate
2、componentWillUpdate
3、render
4、componentDidUpdate
017、当组件的key值发生改变后会执行哪些生命周期函数?
1、componentWillUnmount
2、constructor
3、componentWillMount
4、render
5、componentDidMount
018、在react中是否封装过组件?封装组件需要注意的地方?
常用封装组件用到的东西
1、propTypes 限制外部数据的类型
2、defaultProps 设置默认的外部数据
3、父传子 子传父 context 等传值方式
4、高阶组件
封装组件的时候一定要注意组件的复用性,灵活性
019、如何接收组件内部的标签/内容
通过this.props.children
020、请说下你对redux的理解,以及使用的方式
其实redux就是Flux的一种进阶实现。它是一个应用数据流框架,
主要作用应用状态的管理
redux的三大原则
1、单一的数据源
2、state是只读的
3、使用纯函数来进行修改redux中有
3个常用的方法
1、createStore() 创建store
2、combineReducers() 合并多个reducer
3、applyMiddleware() 使用中间件,处理异步的action
redux数据传递的流程
当组件需要改变Store数据的时候。需要创建一个Action,然后通过dispatch(action) 传递给Store,然后Store把Action转发给Reducers.Reducers会拿到previousState(以前的state
数据) 和action。然后将previousState和action进行结合做新的数据(store)修改。然后生成一个新的数据传递给Store 。Store通过触发subscribe()这个方法来调用函数执行setState使得view的视图发生改变
001、请说下在react中如何处理异步的action
通过applyMiddleware来使用中间件来处理action
常用的中间件
redux-promise-middleware
redux-thunk
redux-saga
002、请说下redux中中间件的理解
中间件:请求和回复之间的一个应用。
在redux中中间件是dispatch与reducer之间的一个应用
003、请说下redux中你对reducers的理解,以及如何合并多个reducers
在redux中reducer是一个纯函数,其中这个纯函数会接收
2个参数一个是state一个是action。state用来保存公共的状态,state有一个特点就是只允许读不允许进行修改 。在实际开发中因为会涉及到多人协作开发所以每个模块都会有一个reducer。
我们可以通过combineReducers来合并多个reducers
004、请说下你对高阶组件的理解,以及作用高阶组件就是接受一个组件作为参数,返回一个相对增强性的组件的函数高阶组件是一个函数 并不是组件
作用:
1、属性代理
---主要进行组件的复用
2、反向集成
---主要进行渲染的劫持
005、在react中如何解决单页面开发首次加载白屏现象
1、通过路由懒加载的方式 react-loadable
2、首屏服务端渲染
006、请说下react中key值的理解
react利用key来识别组件,它是一种身份标识标识,相同的key react认为是同
一个组件,这样后续相同的key对应组件都不会被创建
有了key属性后,就可以与组件建立了一种对应关系,react根据key来决定是销毁
重新创建组件还是更新组件。
key相同,若组件属性有所变化,则react只更新组件对应的属性;没有变化则不
更新。
key值不同,则react先销毁该组件(有状态组件的componentWillUnmount会执行)
,然后重新创建该组件(有状态组件的constructor和componentWillUnmount都会执行)
007、组件第一次执行的时候会执行哪些生命周期函数
constructor
componentWillMount
render
componentDidMount
008、哪些生命周期会执行多次
render
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate
009、当this.state 或者this.props发生改变的时候会执行哪些生命周期函数
this.state
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
this.props
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
010、谈谈你对context的理解
当你不想在组件树中通过逐层传递props或者state的方式来传递数据时,可以使用
Context来实现跨层级的组件数据传递,使用context可以实现跨组件传递
旧版context的基本使用
1、getChildContext根组件中声明,一个函数,返回一个对象, 就是context
2、childContextTypes根组件中声明,指定context的结构类型, 如不指定,会产生错误
3、contextTypes子孙组件中声明,指定要接收的context的结构类型, 可以只是context的一部分结构。contextTypes没有定义,context将是 一个空对象。
4、this.context在子孙组件中通过此来获取上下文
新版
context的基本使用
1、根组件引入GlobalContext,并使用GlobalContext.Provider(生产者)
2、组件引入GlobalContext并调用context,使用GlobalContext.Consumer
011、谈谈你对react中withRouter的理解默认情况下必须是经过路由匹配渲染的组件在
this.props上拥有路由参数,才能使用编程式导航的写法,withRouter是把不是通过路由切换过来的组件,将react-router 的 history、location、match 三个对象传入props对象上
简单的来说就是不是路由包裹的组件也可以使用路由的一些方法
012、说以下你对puerComoponent的理解pureComponent表示一个纯组件,可以用来优化react程序。减少render函数渲染的次数。提高性能
pureComponent进行的是浅比较,也就是说如果是引用数据类型的数据,只会比较不是同一个地址,而不会比较这个地址里面的数据是否一致
好处:当组件更新时,如果组件的props或者
state都没有改变,render函数就不 会触发。省去虚拟DOM的生成和对比过程,达到提升性能的目的。具体原因是因为react自动帮我们做了一层浅比较
013、react请求接口数据是在componentDidMount 还是componentWillMount周期好
如果你要获取外部数据并加载到组件上,只能在组件"已经"挂载到真实的网页上才能作这事情,其它情况你是加载不到组件的。componentDidMount方法中的代码,是在组件已经完全挂载到网页上才会调用被执行,所以可以保证数据的加载React异步渲染开启的时候,componentWillMount 就可能被中途打断,中断之后渲染又要重做一遍,如果在componentWillMount 中做 AJAX 调用,代码里看到只有调用一次,但是实际上可能调用 N 多次,这明显不合适。相反,若把 AJAX 放在componentDidMount,因为 componentDidMount 在第二阶段,所以绝对不会多次重复调用,这才是 AJAX 合适的位置
一、React中key值得作用
react中的key属性,它是一个特殊的属性,它是出现不是给开发者用的,而是给React自己使用,有了key属性后,就可以与组件建立了一种对应关系,简单说,react利用key来识别组件,他是一种身份标识,就像每个人有一个身份证来做辨识一样。每个key 对应一个组件,相同的key react认为是同一个组件,这样后续相同的key对应组件都不会被创建
key值相同
如果两个元素是相同的key,且满足第一点元素类型相同, 若元素属性有所变化,则React只更新组件对应的属性,这种情况下,性能开销会相对较小
key值不同
在render函数执行的时候,新旧两个虚拟DOM会进行对比,如果两个元素有不同的key,那么在前后两次渲染中就会被认为是不同的元素,这时候旧的那个元素会被unmount,新的元素会被mount
//更新前
render(){
return ( <List key = '1'/>);
}
//更新后
render(){
return (
<List key = '2'/>
);
}
二、例子
//tree1
<ul>
<li key='1'>1</li>
<li key='2'>2</li>
</ul>
//tree 2
<ul>
<li key='1'>1</li>
<li key='3'>3</li>
<li key='2'>2</li>
</ul>
如果没有key值得情况下,react并不会执行插入操作,他直接会移除原先的第二个子元素,然后再append进去剩下的子元素,而其实我们这个操作只只需要一个insert操作就能完成。为了解决这种问题,react需要我们提供给一个key来帮助更新,减少性能开销
如果有key值得情况下,react就会通过key来发现tree2的第二个元素不是原先tree1的第二个元素,原先的第二个元素被挪到下面去了,因此在操作的时候就会直接指向insert操作,来减少dom操作的性能开销
三、不推荐用属性中的index来做key值
大部分情况下我们要在执行数组遍历的时候会用index来表示元素的key。这样做其实并不是很合理。我们用key的真实目的是为了标识在前后两次渲染中元素的对应关系,防止发生不必要的更新操作。那么如果我们用index来标识key,数组在执行插入、排序等操作之后,原先的index并不再对应到原先的值,那么这个key就失去了本身的意义,并且会带来其他问题
四、注意事项
React中的key 值必须保证其唯一和稳定性
下面案例中key的值以Math.random() 随机生成而定,这使得数组元素中的每项都重新销毁然后重新创建,有一定的性能开销
{
dataList.map((item,index)=>{
return <div style={mystyle} key={Math.random()}>{item.name}</div>
})
}
一、react-hooks概念
React中一切皆为组件,React中组件分为类组件和函数组件,在React中如果需要记录一个组件的状态的时候,那么这个组件必须是类组件。那么能否让函数组件拥有类组件的功能?这个时候我们就需要使用hooks。
Hooks让我们的函数组件拥有了类似类组件的特性,Hook是React16.8中新增的功能,它们允许您在不编写类的情况下使用状态和其他React功能
二、为什么React中需要类组件
1、需要记录当前组件的状态
2、需要使用组件的一些生命周期函数
二者对比之后是不是感觉Hooks简单好多了?那么接下来我们来学习Hooks
四、Hooks基本使用
1、Hooks常用的方法
useState 、useEffect 、useContext以上三个是hooks经常会用到的一些方法
2、useState
useState是react自带的一个hook函数,它的作用就是用来声明状态变量.useState这个函数接收的参数是我们的状态初始值,它返回了一个数组,这个数组的第 [0]项是当前的状态值,第 [1]项是可以改变状态值的方法函数。
useState : 创建一个状态,这个状态为0
count : 代表当前状态值也就是0
setCount : 更新状态的函数
addCount = ()=>setCount(count+1);调用setCount就可以用来修改状态
2-1、useState返回的是什么?
const[count,setCount] = useState(0);
const state = useState(0);
const count = state[0];
const setCount = state[1]
注意:
1、useState一定要写在函数初始的位置不能在循环或判断语句等里面调用,这样是为了让我们的 Hooks 在每次渲染的时候都会按照 相同的顺序 调用,因为这里有一个关键的问题,那就是 useState 需要依赖参照第一次渲染的调用顺序来匹配对于的state,否则 useState 会无法正确返回它对于的state
2、我们可以在一个函数组件中使用多个
export default()=>{
let[count,setCount] = useState(0);
let[count,setCount] = useState(0);
let[count,setCount] = useState(0);
}
五、useEffect基本使用
我们写的有状态组件,通常会产生很多的副作用(side effect),比如发起ajax请求获取数据,添加一些监听的注册和取消注册,手动修改dom等等。我们之前都把这些副作用的函数写在生命周期函数钩子里,比如componentDidMount,componentDidUpdate和componentWillUnmount。而现在的useEffect就相当与这些声明周期函数钩子的集合体。它以一抵三。
(useEffect = componentDidMount+componentDidUpdate+componentWillUnmount)
5-1、useEffect
useEffect中有两个参数,第一个参数是一个函数,第二个参数是一个依赖的数据。第二个参数用来决定是否执行里面的操作,可以避免一些不必要的性能损失,只要第二个参数中的成员的值没有改变,就会跳过此次执行。如果传入一个空数组 [ ],那么该effect 只会在组件 mount 和 unmount 时期执行。
5-2、useEffect模拟componentDidMount && componentDidUpdate
importReact,{useState,useEffect}from"react"
export default()=>{
let[title,setTitle] = useState(0);
letupdateTitle =()=>setTitle(title+1);
return(
<div>
<h2>{title}</h2>
<button onClick={updateTitle}>点击</button>
</div> )
//参数是一个函数 每次mount 或者 update都会调用当前函数
useEffect(()=>{
document.title =`页面为${count}`;
})
}
5-3、如何只在componentDidMount中执行
import React,{useState,useEffect} from"react" export default()=>{
let[title,setTitle] = useState(0);
let updateTitle =()=>setTitle(title+1);
return(
<div>
<h2>{title}</h2>
<buttononClick={updateTitle}>点击</button>
</div>
)
//将第二个参数设置为一个空数组则只会在componentDidMount中执行
useEffect(
()=>{document.title =`页面为${count}`; },[])}
5-2、useEffect模拟componentWillUnMount
useEffect 中还可以通过让函数返回一个函数来进行一些清理操作,比如取消订阅等
useEffect =(()=>{
return()=>{
//unmount时调用这里
document.removeEventListener();
}
},[])
四、useEffect 什么时候执行?
它会在组件 mount 和 unmount 以及每次重新渲染的时候都会执行,也就是会在 componentDidMount、componentDidUpdate、componentWillUnmount 这三个时期执行
五、hooks的好处
面向生命周期编程变成了面向业务逻辑编程
六、fetch与axios的区别
axios("http://xxx/xxx.json?a=123'").then((res)=>{
consol.log(res)//这里的r是响应结果})
fetch("http://www.baidu.com").then((res)=>{
console.log(res);//是一个综合各种方法的对象,并不是请求的数据
})
fetch返回的是一个未处理的方法集合,我们可以通过这些方法得到我们想要的数据类型。如果我们想要json格式,就执行response.json(),如果我们想要字符串就response.text()
axios
1、从浏览器中创建 XMLHttpRequest
2、从 node.js 发出 http 请求
3、支持 Promise API
4、拦截请求和响应
5、转换请求和响应数据
6、自动转换JSON数据
7、客户端支持防止CSRF/XSRF
fetch:
符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里
更加底层,提供的API丰富(request, response)
脱离了XHR,是ES规范里新的实现方式
1、fetchtch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
2、fetch默认不会带cookie,需要添加配置项
3、fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实
现的超时控制并不能阻止请求过程继续在后台运行,造成了量的浪费
4、fetch没有办法原生监测请求的进度,而XHR可以
来源:https://www.cnblogs.com/yebai/p/11466533.html