说说你用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 treestatepropsrender() 的后果做各种操作。

然而如果渲染 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={};    }  }