说说你用react有什么坑点?
1. JSX做表达式判断时候,须要强转为boolean类型
如果不应用!!b
进行强转数据类型,会在页面外面输入0
。
render() { const b = 0; return <div> { !!b && <div>这是一段文本</div> } </div>}
2. 尽量不要在 componentWillReviceProps
里应用 setState,如果肯定要应用,那么须要判断完结条件,不然会呈现有限重渲染,导致页面解体
3. 给组件增加ref时候,尽量不要应用匿名函数,因为当组件更新的时候,匿名函数会被当做新的prop解决,让ref属性承受到新函数的时候,react外部会先清空ref,也就是会以null为回调参数先执行一次ref这个props,而后在以该组件的实例执行一次ref,所以用匿名函数做ref的时候,有的时候去ref赋值后的属性会取到null
4. 遍历子节点的时候,不要用 index 作为组件的 key 进行传入
React中的props为什么是只读的?
this.props
是组件之间沟通的一个接口,原则上来讲,它只能从父组件流向子组件。React具备浓厚的函数式编程的思维。
提到函数式编程就要提一个概念:纯函数。它有几个特点:
- 给定雷同的输出,总是返回雷同的输入。
- 过程没有副作用。
- 不依赖内部状态。
this.props
就是吸取了纯函数的思维。props的不能够变性就保障的雷同的输出,页面显示的内容是一样的,并且不会产生副作用
高阶组件存在的问题
- 静态方法失落(必须将静态方法做拷贝)
refs
属性不能透传(如果你向一个由高阶组件创立的组件的元素增加ref
援用,那么ref
指向的是最外层容器组件实例的,而不是被包裹的WrappedComponent
组件。)- 反向继承不能保障残缺的子组件树被解析
React 组件有两种模式,别离是 class 类型和 function 类型(无状态组件)。
咱们晓得反向继承的渲染劫持能够管制 WrappedComponent
的渲染过程,也就是说这个过程中咱们能够对 elements tree
、 state
、 props
或 render()
的后果做各种操作。
然而如果渲染 elements tree
中蕴含了 function 类型的组件的话,这时候就不能操作组件的子组件了。
对有状态组件和无状态组件的了解及应用场景
(1)有状态组件
特点:
- 是类组件
- 有继承
- 能够应用this
- 能够应用react的生命周期
- 应用较多,容易频繁触发生命周期钩子函数,影响性能
- 外部应用 state,保护本身状态的变动,有状态组件依据内部组件传入的 props 和本身的 state进行渲染。
应用场景:
- 须要应用到状态的。
- 须要应用状态操作组件的(无状态组件的也能够实现新版本react hooks也可实现)
总结: 类组件能够保护本身的状态变量,即组件的 state ,类组件还有不同的生命周期办法,能够让开发者可能在组件的不同阶段(挂载、更新、卸载),对组件做更多的管制。类组件则既能够充当无状态组件,也能够充当有状态组件。当一个类组件不须要治理本身状态时,也可称为无状态组件。
(2)无状态组件 特点:
- 不依赖本身的状态state
- 能够是类组件或者函数组件。
- 能够完全避免应用 this 关键字。(因为应用的是箭头函数事件无需绑定)
- 有更高的性能。当不须要应用生命周期钩子时,应该首先应用无状态函数组件
- 组件外部不保护 state ,只依据内部组件传入的 props 进行渲染的组件,当 props 扭转时,组件从新渲染。
应用场景:
- 组件不须要治理 state,纯展现
长处:
- 简化代码、专一于 render
- 组件不须要被实例化,无生命周期,晋升性能。 输入(渲染)只取决于输出(属性),无副作用
- 视图和数据的解耦拆散
毛病:
- 无奈应用 ref
- 无生命周期办法
- 无法控制组件的重渲染,因为无奈应用shouldComponentUpdate 办法,当组件承受到新的属性时则会重渲染
总结: 组件外部状态且与内部无关的组件,能够思考用状态组件,这样状态树就不会过于简单,易于了解和治理。当一个组件不须要治理本身状态时,也就是无状态组件,应该优先设计为函数组件。比方自定义的 <Button/>
、 <Input />
等组件。
什么是受控组件和非受控组件
- 受状态管制的组件,必须要有onChange办法,否则不能应用 受控组件能够赋予默认值(官网举荐应用 受控组件) 实现双向数据绑定
class Input extends Component{ constructor(){ super(); this.state = {val:'100'} } handleChange = (e) =>{ //e是事件源 let val = e.target.value; this.setState({val}); }; render(){ return (<div> <input type="text" value={this.state.val} onChange={this.handleChange}/> {this.state.val} </div>) }}
- 非受控也就意味着我能够不须要设置它的state属性,而通过ref来操作实在的DOM
class Sum extends Component{ constructor(){ super(); this.state = {result:''} } //通过ref设置的属性 能够通过this.refs获取到对应的dom元素 handleChange = () =>{ let result = this.refs.a.value + this.b.value; this.setState({result}); }; render(){ return ( <div onChange={this.handleChange}> <input type="number" ref="a"/> {/*x代表的实在的dom,把元素挂载在了以后实例上*/} <input type="number" ref={(x)=>{ this.b = x; }}/> {this.state.result} </div> ) }}
React 16中新生命周期有哪些
对于 React16 开始利用的新生命周期: 能够看出,React16 自上而下地对生命周期做了另一种维度的解读:
- Render 阶段:用于计算一些必要的状态信息。这个阶段可能会被 React 暂停,这一点和 React16 引入的 Fiber 架构(咱们前面会重点解说)是无关的;
- Pre-commit阶段:所谓“commit”,这里指的是“更新真正的 DOM 节点”这个动作。所谓 Pre-commit,就是说我在这个阶段其实还并没有去更新实在的 DOM,不过 DOM 信息曾经是能够读取的了;
- Commit 阶段:在这一步,React 会实现实在 DOM 的更新工作。Commit 阶段,咱们能够拿到实在 DOM(包含 refs)。
与此同时,新的生命周期在流程方面,依然遵循“挂载”、“更新”、“卸载”这三个狭义的划分形式。它们别离对应到:
挂载过程:
- constructor
- getDerivedStateFromProps
- render
- componentDidMount
更新过程:
- getDerivedStateFromProps
- shouldComponentUpdate
- render
- getSnapshotBeforeUpdate
- componentDidUpdate
卸载过程:
- componentWillUnmount
参考 前端进阶面试题具体解答
React中什么是受控组件和非控组件?
(1)受控组件 在应用表单来收集用户输出时,例如<input><select><textearea>
等元素都要绑定一个change事件,当表单的状态发生变化,就会触发onChange事件,更新组件的state。这种组件在React中被称为受控组件,在受控组件中,组件渲染出的状态与它的value或checked属性绝对应,react通过这种形式打消了组件的部分状态,使整个状态可控。react官网举荐应用受控表单组件。
受控组件更新state的流程:
- 能够通过初始state中设置表单的默认值
- 每当表单的值发生变化时,调用onChange事件处理器
- 事件处理器通过事件对象e拿到扭转后的状态,并更新组件的state
- 一旦通过setState办法更新state,就会触发视图的从新渲染,实现表单组件的更新
受控组件缺点: 表单元素的值都是由React组件进行治理,当有多个输入框,或者多个这种组件时,如果想同时获取到全副的值就必须每个都要编写事件处理函数,这会让代码看着很臃肿,所以为了解决这种状况,呈现了非受控组件。
(2)非受控组件 如果一个表单组件没有value props(单选和复选按钮对应的是checked props)时,就能够称为非受控组件。在非受控组件中,能够应用一个ref来从DOM取得表单值。而不是为每个状态更新编写一个事件处理程序。
React官网的解释:
要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你能够应用 ref来从 DOM 节点中获取表单数据。
因为非受控组件将实在数据贮存在 DOM 节点中,所以在应用非受控组件时,有时候反而更容易同时集成 React 和非 React 代码。如果你不介意代码好看性,并且心愿疾速编写代码,应用非受控组件往往能够缩小你的代码量。否则,你应该应用受控组件。
例如,上面的代码在非受控组件中接管单个属性:
class NameForm extends React.Component { constructor(props) { super(props); this.handleSubmit = this.handleSubmit.bind(this); } handleSubmit(event) { alert('A name was submitted: ' + this.input.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input type="text" ref={(input) => this.input = input} /> </label> <input type="submit" value="Submit" /> </form> ); }}
总结: 页面中所有输出类的DOM如果是现用现取的称为非受控组件,而通过setState将输出的值保护到了state中,须要时再从state中取出,这里的数据就受到了state的管制,称为受控组件。
Redux 中异步的申请怎么解决
能够在 componentDidmount 中间接进⾏申请⽆须借助redux。然而在⼀定规模的项⽬中,上述⽅法很难进⾏异步流的治理,通常状况下咱们会借助redux的异步中间件进⾏异步解决。redux异步流中间件其实有很多,当下支流的异步中间件有两种redux-thunk、redux-saga。
(1)应用react-thunk中间件
redux-thunk长处:
- 体积⼩: redux-thunk的实现⽅式很简略,只有不到20⾏代码
- 使⽤简略: redux-thunk没有引⼊像redux-saga或者redux-observable额定的范式,上⼿简略
redux-thunk缺点:
- 样板代码过多: 与redux自身⼀样,通常⼀个申请须要⼤量的代码,⽽且很多都是反复性质的
- 耦合重大: 异步操作与redux的action偶合在⼀起,不⽅便治理
- 性能孱弱: 有⼀些理论开发中常⽤的性能须要⾃⼰进⾏封装
应用步骤:
- 配置中间件,在store的创立中配置
import {createStore, applyMiddleware, compose} from 'redux';import reducer from './reducer';import thunk from 'redux-thunk'// 设置调试工具const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;// 设置中间件const enhancer = composeEnhancers( applyMiddleware(thunk));const store = createStore(reducer, enhancer);export default store;
- 增加一个返回函数的actionCreator,将异步申请逻辑放在外面
/** 发送get申请,并生成相应action,更新store的函数 @param url {string} 申请地址 @param func {function} 真正须要生成的action对应的actionCreator @return {function} */// dispatch为主动接管的store.dispatch函数 export const getHttpAction = (url, func) => (dispatch) => { axios.get(url).then(function(res){ const action = func(res.data) dispatch(action) })}
- 生成action,并发送action
componentDidMount(){ var action = getHttpAction('/getData', getInitTodoItemAction) // 发送函数类型的action时,该action的函数领会主动执行 store.dispatch(action)}
(2)应用redux-saga中间件
redux-saga长处:
- 异步解耦: 异步操作被被转移到独自 saga.js 中,不再是掺杂在 action.js 或 component.js 中
- action解脱thunk function: dispatch 的参数仍然是⼀个纯正的 action (FSA),⽽不是充斥 “⿊魔法” thunk function
- 异样解决: 受害于 generator function 的 saga 实现,代码异样/申请失败 都能够间接通过 try/catch 语法间接捕捉解决
- 性能强⼤: redux-saga提供了⼤量的Saga 辅助函数和Effect 创立器供开发者使⽤,开发者⽆须封装或者简略封装即可使⽤
- 灵便: redux-saga能够将多个Saga能够串⾏/并⾏组合起来,造成⼀个⾮常实⽤的异步flow
- 易测试,提供了各种case的测试⽅案,包含mock task,分⽀笼罩等等
redux-saga缺点:
- 额定的学习老本: redux-saga不仅在使⽤难以了解的 generator function,⽽且无数⼗个API,学习老本远超redux-thunk,最重要的是你的额定学习老本是只服务于这个库的,与redux-observable不同,redux-observable尽管也有额定学习老本然而背地是rxjs和⼀整套思维
- 体积庞⼤: 体积略⼤,代码近2000⾏,min版25KB左右
- 性能过剩: 实际上并发管制等性能很难⽤到,然而咱们仍然须要引⼊这些代码
- ts⽀持不敌对: yield⽆法返回TS类型
redux-saga能够捕捉action,而后执行一个函数,那么能够把异步代码放在这个函数中,应用步骤如下:
- 配置中间件
import {createStore, applyMiddleware, compose} from 'redux';import reducer from './reducer';import createSagaMiddleware from 'redux-saga'import TodoListSaga from './sagas'const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;const sagaMiddleware = createSagaMiddleware()const enhancer = composeEnhancers( applyMiddleware(sagaMiddleware));const store = createStore(reducer, enhancer);sagaMiddleware.run(TodoListSaga)export default store;
- 将异步申请放在sagas.js中
import {takeEvery, put} from 'redux-saga/effects'import {initTodoList} from './actionCreator'import {GET_INIT_ITEM} from './actionTypes'import axios from 'axios'function* func(){ try{ // 能够获取异步返回数据 const res = yield axios.get('/getData') const action = initTodoList(res.data) // 将action发送到reducer yield put(action) }catch(e){ console.log('网络申请失败') }}function* mySaga(){ // 主动捕捉GET_INIT_ITEM类型的action,并执行func yield takeEvery(GET_INIT_ITEM, func)}export default mySaga
- 发送action
componentDidMount(){ const action = getInitTodoItemAction() store.dispatch(action)}
对 React-Intl 的了解,它的工作原理?
React-intl是雅虎的语言国际化开源我的项目FormatJS的一部分,通过其提供的组件和API能够与ReactJS绑定。
React-intl提供了两种应用办法,一种是援用React组件,另一种是间接调取API,官网更加举荐在React我的项目中应用前者,只有在无奈应用React组件的中央,才应该调用框架提供的API。它提供了一系列的React组件,包含数字格式化、字符串格式化、日期格式化等。
在React-intl中,能够配置不同的语言包,他的工作原理就是依据须要,在语言包之间进行切换。
对 React context 的了解
在React中,数据传递个别应用props传递数据,维持单向数据流,这样能够让组件之间的关系变得简略且可预测,然而单项数据流在某些场景中并不实用。单纯一对的父子组件传递并无问题,但要是组件之间层层依赖深刻,props就须要层层传递显然,这样做太繁琐了。
Context 提供了一种在组件之间共享此类值的形式,而不用显式地通过组件树的逐层传递 props。
能够把context当做是特定一个组件树内共享的store,用来做数据传递。简略说就是,当你不想在组件树中通过逐层传递props或者state的形式来传递数据时,能够应用Context来实现跨层级的组件数据传递。
JS的代码块在执行期间,会创立一个相应的作用域链,这个作用域链记录着运行时JS代码块执行期间所能拜访的流动对象,包含变量和函数,JS程序通过作用域链拜访到代码块外部或者内部的变量和函数。
如果以JS的作用域链作为类比,React组件提供的Context对象其实就好比一个提供给子组件拜访的作用域,而 Context对象的属性能够看成作用域上的流动对象。因为组件 的 Context 由其父节点链上所有组件通 过 getChildContext()返回的Context对象组合而成,所以,组件通过Context是能够拜访到其父组件链上所有节点组件提供的Context的属性。
为什么React并不举荐优先思考应用Context?
- Context目前还处于试验阶段,可能会在前面的发行版本中有很大的变动,事实上这种状况曾经产生了,所以为了防止给今后降级带来大的影响和麻烦,不倡议在app中应用context。
- 只管不倡议在app中应用context,然而独有组件而言,因为影响范畴小于app,如果能够做到高内聚,不毁坏组件树之间的依赖关系,能够思考应用context
- 对于组件之间的数据通信或者状态治理,无效应用props或者state解决,而后再思考应用第三方的成熟库进行解决,以上的办法都不是最佳的计划的时候,在思考context。
- context的更新须要通过setState()触发,然而这并不是很牢靠的,Context反对跨组件的拜访,然而如果两头的子组件通过一些办法不影响更新,比方 shouldComponentUpdate() 返回false 那么不能保障Context的更新肯定能够应用Context的子组件,因而,Context的可靠性须要关注
React中refs的作用是什么?有哪些利用场景?
Refs 提供了一种形式,用于拜访在 render 办法中创立的 React 元素或 DOM 节点。Refs 应该审慎应用,如下场景应用 Refs 比拟适宜:
- 解决焦点、文本抉择或者媒体的管制
- 触发必要的动画
- 集成第三方 DOM 库
Refs 是应用 React.createRef()
办法创立的,他通过 ref
属性附加到 React 元素上。要在整个组件中应用 Refs,须要将 ref
在构造函数中调配给其实例属性:
class MyComponent extends React.Component { constructor(props) { super(props) this.myRef = React.createRef() } render() { return <div ref={this.myRef} /> }}
因为函数组件没有实例,因而不能在函数组件上间接应用 ref
:
function MyFunctionalComponent() { return <input />;}class Parent extends React.Component { constructor(props) { super(props); this.textInput = React.createRef(); } render() { // 这将不会工作! return ( <MyFunctionalComponent ref={this.textInput} /> ); }}
但能够通过闭合的帮忙在函数组件外部进行应用 Refs:
function CustomTextInput(props) { // 这里必须申明 textInput,这样 ref 回调才能够援用它 let textInput = null; function handleClick() { textInput.focus(); } return ( <div> <input type="text" ref={(input) => { textInput = input; }} /> <input type="button" value="Focus the text input" onClick={handleClick} /> </div> ); }
留神:
- 不应该适度的应用 Refs
ref
的返回值取决于节点的类型:- 当
ref
属性被用于一个一般的 HTML 元素时,React.createRef()
将接管底层 DOM 元素作为他的current
属性以创立ref
。 - 当
ref
属性被用于一个自定义的类组件时,ref
对象将接管该组件已挂载的实例作为他的current
。
- 当
- 当在父组件中须要拜访子组件中的
ref
时可应用传递 Refs 或回调 Refs。
React申明组件有哪几种办法,有什么不同?
React 申明组件的三种形式:
- 函数式定义的
无状态组件
- ES5原生形式
React.createClass
定义的组件 - ES6模式的
extends React.Component
定义的组件
(1)无状态函数式组件 它是为了创立纯展现组件,这种组件只负责依据传入的props来展现,不波及到state状态的操作
组件不会被实例化,整体渲染性能失去晋升,不能拜访this对象,不能拜访生命周期的办法
(2)ES5 原生形式 React.createClass // RFC React.createClass会自绑定函数办法,导致不必要的性能开销,减少代码过期的可能性。
(3)E6继承模式 React.Component // RCC 目前极为举荐的创立有状态组件的形式,最终会取代React.createClass模式;绝对于 React.createClass能够更好实现代码复用。
无状态组件绝对于于后者的区别: 与无状态组件相比,React.createClass和React.Component都是创立有状态的组件,这些组件是要被实例化的,并且能够拜访组件的生命周期办法。
React.createClass与React.Component区别:
① 函数this自绑定
- React.createClass创立的组件,其每一个成员函数的this都有React主动绑定,函数中的this会被正确设置。
- React.Component创立的组件,其成员函数不会主动绑定this,须要开发者手动绑定,否则this不能获取以后组件实例对象。
② 组件属性类型propTypes及其默认props属性defaultProps配置不同
- React.createClass在创立组件时,无关组件props的属性类型及组件默认的属性会作为组件实例的属性来配置,其中defaultProps是应用getDefaultProps的办法来获取默认组件属性的
- React.Component在创立组件时配置这两个对应信息时,他们是作为组件类的属性,不是组件实例的属性,也就是所谓的类的动态属性来配置的。
③ 组件初始状态state的配置不同
- React.createClass创立的组件,其状态state是通过getInitialState办法来配置组件相干的状态;
- React.Component创立的组件,其状态state是在constructor中像初始化组件属性一样申明的。
React中发动网络申请应该在哪个生命周期中进行?为什么?
对于异步申请,最好放在componentDidMount中去操作,对于同步的状态扭转,能够放在componentWillMount中,个别用的比拟少。
如果认为在componentWillMount里发动申请能提前取得后果,这种想法其实是谬误的,通常componentWillMount比componentDidMount早不了多少微秒,网络上任何一点提早,这一点差别都可忽略不计。
react的生命周期: constructor() -> componentWillMount() -> render() -> componentDidMount()
下面这些办法的调用是有秩序的,由上而下顺次调用。
- constructor被调用是在组件筹备要挂载的最开始,此时组件尚未挂载到网页上。
- componentWillMount办法的调用在constructor之后,在render之前,在这办法里的代码调用setState办法不会触发从新render,所以它个别不会用来作加载数据之用。
- componentDidMount办法中的代码,是在组件曾经齐全挂载到网页上才会调用被执行,所以能够保证数据的加载。此外,在这办法中调用setState办法,会触发从新渲染。所以,官网设计这个办法就是用来加载内部数据用的,或解决其余的副作用代码。与组件上的数据无关的加载,也能够在constructor里做,但constructor是做组件state初绐化工作,并不是做加载数据这工作的,constructor里也不能setState,还有加载的工夫太长或者出错,页面就无奈加载进去。所以有副作用的代码都会集中在componentDidMount办法里。
总结:
- 跟服务器端渲染(同构)有关系,如果在componentWillMount外面获取数据,fetch data会执行两次,一次在服务器端一次在客户端。在componentDidMount中能够解决这个问题,componentWillMount同样也会render两次。
- 在componentWillMount中fetch data,数据肯定在render后能力达到,如果遗记了设置初始状态,用户体验不好。
- react16.0当前,componentWillMount可能会被执行屡次。
在React中组件的props扭转时更新组件的有哪些办法?
在一个组件传入的props更新时从新渲染该组件罕用的办法是在componentWillReceiveProps
中将新的props更新到组件的state中(这种state被成为派生状态(Derived State)),从而实现从新渲染。React 16.3中还引入了一个新的钩子函数getDerivedStateFromProps
来专门实现这一需要。
(1)componentWillReceiveProps(已废除)
在react的componentWillReceiveProps(nextProps)生命周期中,能够在子组件的render函数执行前,通过this.props获取旧的属性,通过nextProps获取新的props,比照两次props是否雷同,从而更新子组件本人的state。
这样的益处是,能够将数据申请放在这里进行执行,须要传的参数则从componentWillReceiveProps(nextProps)中获取。而不用将所有的申请都放在父组件中。于是该申请只会在该组件渲染时才会收回,从而加重申请累赘。
(2)getDerivedStateFromProps(16.3引入)
这个生命周期函数是为了代替componentWillReceiveProps
存在的,所以在须要应用componentWillReceiveProps
时,就能够思考应用getDerivedStateFromProps
来进行代替。
两者的参数是不雷同的,而getDerivedStateFromProps
是一个动态函数,也就是这个函数不能通过this拜访到class的属性,也并不举荐间接拜访属性。而是应该通过参数提供的nextProps以及prevState来进行判断,依据新传入的props来映射到state。
须要留神的是,如果props传入的内容不须要影响到你的state,那么就须要返回一个null,这个返回值是必须的,所以尽量将其写到函数的开端:
static getDerivedStateFromProps(nextProps, prevState) { const {type} = nextProps; // 当传入的type发生变化的时候,更新state if (type !== prevState.type) { return { type, }; } // 否则,对于state不进行任何操作 return null;}
解释 React 中 render() 的目标。
每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的示意。如果须要渲染多个 HTML 元素,则必须将它们组合在一个关闭标记内,例如 <form>
、<group>
、<div>
等。此函数必须放弃污浊,即必须每次调用时都返回雷同的后果。
哪些办法会触发 React 从新渲染?从新渲染 render 会做些什么?
(1)哪些办法会触发 react 从新渲染?
- setState()办法被调用
setState 是 React 中最罕用的命令,通常状况下,执行 setState 会触发 render。然而这里有个点值得关注,执行 setState 的时候不肯定会从新渲染。当 setState 传入 null 时,并不会触发 render。
class App extends React.Component { state = { a: 1 }; render() { console.log("render"); return ( <React.Fragement> <p>{this.state.a}</p> <button onClick={() => { this.setState({ a: 1 }); // 这里并没有扭转 a 的值 }} > Click me </button> <button onClick={() => this.setState(null)}>setState null</button> <Child /> </React.Fragement> ); }}
- 父组件从新渲染
只有父组件从新渲染了,即便传入子组件的 props 未发生变化,那么子组件也会从新渲染,进而触发 render
(2)从新渲染 render 会做些什么?
- 会对新旧 VNode 进行比照,也就是咱们所说的Diff算法。
- 对新旧两棵树进行一个深度优先遍历,这样每一个节点都会一个标记,在到深度遍历的时候,每遍历到一和个节点,就把该节点和新的节点树进行比照,如果有差别就放到一个对象外面
- 遍历差别对象,依据差别的类型,依据对应对规定更新VNode
React 的解决 render 的根本思维模式是每次一有变动就会去从新渲染整个利用。在 Virtual DOM 没有呈现之前,最简略的办法就是间接调用 innerHTML。Virtual DOM厉害的中央并不是说它比间接操作 DOM 快,而是说不论数据怎么变,都会尽量以最小的代价去更新 DOM。React 将 render 函数返回的虚构 DOM 树与老的进行比拟,从而确定 DOM 要不要更新、怎么更新。当 DOM 树很大时,遍历两棵树进行各种比对还是相当耗性能的,特地是在顶层 setState 一个渺小的批改,默认会去遍历整棵树。只管 React 应用高度优化的 Diff 算法,然而这个过程依然会损耗性能.
React.Children.map和js的map有什么区别?
JavaScript中的map不会对为null或者undefined的数据进行解决,而React.Children.map中的map能够解决React.Children为null或者undefined的状况。
useEffect和useLayoutEffect的区别
useEffect
基本上90%的状况下,都应该用这个,这个是在render完结后,你的callback函数执行,然而不会block browser painting,算是某种异步的形式吧,然而class的componentDidMount 和componentDidUpdate是同步的,在render完结后就运行,useEffect在大部分场景下都比class的形式性能更好.
useLayoutEffect
这个是用在解决DOM的时候,当你的useEffect外面的操作须要解决DOM,并且会扭转页面的款式,就须要用这个,否则可能会呈现呈现闪屏问题, useLayoutEffect外面的callback函数会在DOM更新实现后立刻执行,然而会在浏览器进行任何绘制之前运行实现,阻塞了浏览器的绘制.
React中constructor和getInitialState的区别?
两者都是用来初始化state的。前者是ES6中的语法,后者是ES5中的语法,新版本的React中曾经废除了该办法。
getInitialState是ES5中的办法,如果应用createClass办法创立一个Component组件,能够主动调用它的getInitialState办法来获取初始化的State对象,
var APP = React.creatClass ({ getInitialState() { return { userName: 'hi', userId: 0 }; }})
React在ES6的实现中去掉了getInitialState这个hook函数,规定state在constructor中实现,如下:
Class App extends React.Component{ constructor(props){ super(props); this.state={}; } }