diff算法是怎么运作

每一种节点类型有本人的属性,也就是prop,每次进行diff的时候,react会先比拟该节点类型,如果节点类型不一样,那么react会间接删除该节点,而后间接创立新的节点插入到其中,如果节点类型一样,那么会比拟prop是否有更新,如果有prop不一样,那么react会断定该节点有更新,那么重渲染该节点,而后在对其子节点进行比拟,一层一层往下,直到没有子节点

react和vue的区别

相同点:

  1. 数据驱动页面,提供响应式的试图组件
  2. 都有virtual DOM,组件化的开发,通过props参数进行父子之间组件传递数据,都实现了webComponents标准
  3. 数据流动单向,都反对服务器的渲染SSR
  4. 都有反对native的办法,react有React native, vue有wexx

不同点:

  1. 数据绑定:Vue实现了双向的数据绑定,react数据流动是单向的
  2. 数据渲染:大规模的数据渲染,react更快
  3. 应用场景:React配合Redux架构适宜大规模多人合作简单我的项目,Vue适宜小快的我的项目
  4. 开发格调:react举荐做法jsx + inline style把html和css都写在js了
vue是采纳webpack +vue-loader单文件组件格局,html, js, css同一个文件

在哪个生命周期中你会收回Ajax申请?为什么?

Ajax申请应该写在组件创立期的第五个阶段,即 componentDidMount生命周期办法中。起因如下。
在创立期的其余阶段,组件尚未渲染实现。而在存在期的5个阶段,又不能确保生命周期办法肯定会执行(如通过 shouldComponentUpdate办法优化更新等)。在销毀期,组件行将被销毁,申请数据变得无意义。因而在这些阶段发岀Ajax申请显然不是最好的抉择。
在组件尚未挂载之前,Ajax申请将无奈执行结束,如果此时发出请求,将意味着在组件挂载之前更新状态(如执行 setState),这通常是不起作用的。
在 componentDidMount办法中,执行Ajax即可保障组件曾经挂载,并且可能失常更新组件。

简述flux 思维

Flux 的最大特点,就是数据的"单向流动"。
  • 用户拜访 View
  • View收回用户的 Action
  • Dispatcher 收到Action,要求 Store 进行相应的更新
  • Store 更新后,收回一个"change"事件
  • View 收到"change"事件后,更新页面

说说 React组件开发中对于作用域的常见问题。

在 EMAScript5语法标准中,对于作用域的常见问题如下。
(1)在map等办法的回调函数中,要绑定作用域this(通过bind办法)。
(2)父组件传递给子组件办法的作用域是父组件实例化对象,无奈扭转。
(3)组件事件回调函数办法的作用域是组件实例化对象(绑定父组件提供的办法就是父组件实例化对象),无奈扭转。
在 EMAScript6语法标准中,对于作用域的常见问题如下。
(1)当应用箭头函数作为map等办法的回调函数时,箭头函数的作用域是以后组件的实例化对象(即箭头函数的作用域是定义时的作用域),毋庸绑定作用域。
(2)事件回调函数要绑定组件作用域。
(3)父组件传递办法要绑定父组件作用域。
总之,在 EMAScript6语法标准中,组件办法的作用域是能够扭转的。

如何用 React构建( build)生产模式?

通常,应用 Webpack的 DefinePlugin办法将 NODE ENV设置为 production。这将剥离 propType验证和额定的正告。除此之外,还能够缩小代码,因为 React应用 Uglify的dead-code来打消开发代码和正文,这将大大减少包占用的空间。

参考 前端进阶面试题具体解答

如何防止反复发动ajax获取数据?

  • 数据放在redux外面

React如何进行组件/逻辑复用?

抛开曾经被官网弃用的Mixin,组件形象的技术目前有三种比拟支流:
  • 高阶组件:

    • 属性代理
    • 反向继承
  • 渲染属性
  • react-hooks

setState到底是异步还是同步?

先给出答案: 有时体现出异步,有时体现出同步
  • setState只在合成事件和钩子函数中是“异步”的,在原生事件和setTimeout 中都是同步的
  • setState 的“异步”并不是说外部由异步代码实现,其实自身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用程序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,造成了所谓的“异步”,当然能够通过第二个参数setState(partialState, callback)中的callback拿到更新后的后果
  • setState 的批量更新优化也是建设在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行屡次setStatesetState的批量更新策略会对其进行笼罩,取最初一次的执行,如果是同时setState多个不同的值,在更新时会对其进行合并批量更新

Redux 中间件原理

  • 指的是action和store之间,沟通的桥梁就是dispatch,action就是个对象。比方你用了redux-thunk,action也能够是个函数,怎么实现这个过程,就是通过中间件这个桥梁帮你实现的。action达到store之前会走中间件,这个中间件会把函数式的action转化为一个对象,在传递给store

HOC(高阶组件)

HOC(Higher Order Componennt) 是在 React 机制下社区造成的一种组件模式,在很多第三方开源库中体现弱小。

简述:

  • 高阶组件不是组件,是 加强函数,能够输出一个元组件,返回出一个新的加强组件;
  • 高阶组件的次要作用是 代码复用,操作 状态和参数;

用法:

  • 属性代理 (Props Proxy): 返回出一个组件,它基于被包裹组件进行 性能加强;
  • 默认参数: 能够为组件包裹一层默认参数;
function proxyHoc(Comp) {    return class extends React.Component {        render() {            const newProps = {                name: 'tayde',                age: 1,            }            return <Comp {...this.props} {...newProps} />        }    }}
  1. 提取状态: 能够通过 props 将被包裹组件中的 state 依赖外层,例如用于转换受控组件:
function withOnChange(Comp) {    return class extends React.Component {        constructor(props) {            super(props)            this.state = {                name: '',            }        }        onChangeName = () => {            this.setState({                name: 'dongdong',            })        }        render() {            const newProps = {                value: this.state.name,                onChange: this.onChangeName,            }            return <Comp {...this.props} {...newProps} />        }    }}

应用姿态如下,这样就能十分疾速的将一个 Input 组件转化成受控组件。

const NameInput = props => (<input name="name" {...props} />)export default withOnChange(NameInput)

包裹组件: 能够为被包裹元素进行一层包装,

function withMask(Comp) {  return class extends React.Component {      render() {          return (              <div>                  <Comp {...this.props} />                    <div style={{                      width: '100%',                      height: '100%',                      backgroundColor: 'rgba(0, 0, 0, .6)',                  }}               </div>          )      }  }}
反向继承 (Inheritance Inversion): 返回出一个组件,继承于被包裹组件,罕用于以下操作
function IIHoc(Comp) {    return class extends Comp {        render() {            return super.render();        }    };}

渲染劫持 (Render Highjacking)

条件渲染: 依据条件,渲染不同的组件

function withLoading(Comp) {    return class extends Comp {        render() {            if(this.props.isLoading) {                return <Loading />            } else {                return super.render()            }        }    };}

能够间接批改被包裹组件渲染出的 React 元素树

操作状态 (Operate State) : 能够间接通过 this.state 获取到被包裹组件的状态,并进行操作。但这样的操作容易使 state 变得难以追踪,不易保护,审慎应用。

利用场景:

权限管制,通过形象逻辑,对立对页面进行权限判断,按不同的条件进行页面渲染:
function withAdminAuth(WrappedComponent) {    return class extends React.Component {        constructor(props){            super(props)            this.state = {                isAdmin: false,            }        }         async componentWillMount() {            const currentRole = await getCurrentUserRole();            this.setState({                isAdmin: currentRole === 'Admin',            });        }        render() {            if (this.state.isAdmin) {                return <Comp {...this.props} />;            } else {                return (<div>您没有权限查看该页面,请分割管理员!</div>);            }        }    };}

性能监控 ,包裹组件的生命周期,进行对立埋点:

function withTiming(Comp) {    return class extends Comp {        constructor(props) {            super(props);            this.start = Date.now();            this.end = 0;        }        componentDidMount() {            super.componentDidMount && super.componentDidMount();            this.end = Date.now();            console.log(`${WrappedComponent.name} 组件渲染工夫为 ${this.end - this.start} ms`);        }        render() {            return super.render();        }    };}

代码复用,能够将反复的逻辑进行形象。

应用留神:

  • 纯函数: 加强函数应为纯函数,防止侵入批改元组件;
  • 防止用法净化: 现实状态下,应透传元组件的无关参数与事件,尽量保障用法不变;
  • 命名空间: 为 HOC 减少特异性的组件名称,这样能便于开发调试和查找问题;
  • 援用传递 : 如果须要传递元组件的 refs 援用,能够应用React.forwardRef;
  • 静态方法 : 元组件上的静态方法并无奈被主动传出,会导致业务层无奈调用;解决:

    • 函数导出
    • 静态方法赋值
  • 从新渲染: 因为加强函数每次调用是返回一个新组件,因而如果在 Render中应用加强函数,就会导致每次都从新渲染整个HOC,而且之前的状态会失落;

React 中的高阶组件使用了什么设计模式?

应用了装璜模式,高阶组件的使用:

function withWindowWidth(BaseComponent) {  class DerivedClass extends React.Component {    state = {      windowWidth: window.innerWidth,    }    onResize = () => {      this.setState({        windowWidth: window.innerWidth,      })    }    componentDidMount() {      window.addEventListener('resize', this.onResize)    }    componentWillUnmount() {      window.removeEventListener('resize', this.onResize);    }    render() {      return <BaseComponent {...this.props} {...this.state}/>    }  }  return DerivedClass;}const MyComponent = (props) => {  return <div>Window width is: {props.windowWidth}</div>};export default withWindowWidth(MyComponent);

装璜模式的特点是不须要扭转 被装璜对象 自身,而只是在里面套一个外壳接口。JavaScript 目前曾经有了原生装璜器的提案,其用法如下:

@testable   class MyTestableClass {}

在生命周期中的哪一步你应该发动 AJAX 申请

咱们该当将AJAX 申请放到 componentDidMount 函数中执行,次要起因有下
  • React 下一代和谐算法 Fiber 会通过开始或进行渲染的形式优化利用性能,其会影响到 componentWillMount 的触发次数。对于 componentWillMount 这个生命周期函数的调用次数会变得不确定,React 可能会屡次频繁调用 componentWillMount。如果咱们将 AJAX 申请放到 componentWillMount 函数中,那么不言而喻其会被触发屡次,天然也就不是好的抉择。
  • 如果咱们将AJAX 申请搁置在生命周期的其余函数中,咱们并不能保障申请仅在组件挂载结束后才会要求响应。如果咱们的数据申请在组件挂载之前就实现,并且调用了setState函数将数据增加到组件状态中,对于未挂载的组件则会报错。而在 componentDidMount 函数中进行 AJAX 申请则能无效防止这个问题

你了解“在React中,一切都是组件”这句话。

组件是 React 利用 UI 的构建块。这些组件将整个 UI 分成小的独立并可重用的局部。每个组件彼此独立,而不会影响 UI 的其余部分。

组件更新有几种办法

  • this.setState() 批改状态的时候 会更新组件
  • this.forceUpdate() 强制更新
  • 组件件render之后,子组件应用到父组件中状态,导致子组件的props属性产生扭转的时候 也会触发子组件的更新

组件之间传值

  • 父组件给子组件传值

    在父组件中用标签属性的=模式传值

    在子组件中应用props来获取值

  • 子组件给父组件传值

    在组件中传递一个函数

    在子组件中用props来获取传递的函数,而后执行该函数

    在执行函数的时候把须要传递的值当成函数的实参进行传递

  • 兄弟组件之间传值

    利用父组件

    先把数据通过 【子组件】===》【父组件】

    而后在数据通过 【父组件】===〉【子组件】

    音讯订阅

    应用PubSubJs插件

(在构造函数中)调用 super(props) 的目标是什么

super() 被调用之前,子类是不能应用 this 的,在 ES2015 中,子类必须在 constructor 中调用 super()。传递 propssuper() 的起因则是便于(在子类中)能在 constructor 拜访 this.props

diff 虚构DOM 比拟的规定

  • 【旧虚构DOM】 与 【新虚构DOM】中雷同key

    若虚构DOM中的内容没有产生扭转,间接应用旧的虚构DOM

    若虚构DOM中的内容产生扭转了,则生成新实在的DOM,随后替换页面中之前的实在DOM

  • 【旧虚构DOM】 中未找到 与 【新虚构DOM】雷同的key

    依据数据创立实在DOM,随后渲染到页面

React 性能优化在哪个生命周期?它优化的原理是什么?

react的父级组件的render函数从新渲染会引起子组件的render办法的从新渲染。然而,有的时候子组件的承受父组件的数据没有变动。子组件render的执行会影响性能,这时就能够应用shouldComponentUpdate来解决这个问题。

应用办法如下:

shouldComponentUpdate(nexrProps) {    if (this.props.num === nexrProps.num) {        return false    }    return true;}

shouldComponentUpdate提供了两个参数nextProps和nextState,示意下一次props和一次state的值,当函数返回false时候,render()办法不执行,组件也就不会渲染,返回true时,组件照常重渲染。此办法就是拿以后props中值和下一次props中的值进行比照,数据相等时,返回false,反之返回true。

须要留神,在进行新旧比照的时候,是浅比照,也就是说如果比拟的数据时援用数据类型,只有数据的援用的地址没变,即便内容变了,也会被断定为true。

面对这个问题,能够应用如下办法进行解决:
(1)应用setState扭转数据之前,先采纳ES6中assgin进行拷贝,然而assgin只深拷贝的数据的第一层,所以说不是最完满的解决办法:

const o2 = Object.assign({},this.state.obj)    o2.student.count = '00000';    this.setState({        obj: o2,    })

(2)应用JSON.parse(JSON.stringfy())进行深拷贝,然而遇到数据为undefined和函数时就会错。

const o2 = JSON.parse(JSON.stringify(this.state.obj))    o2.student.count = '00000';    this.setState({        obj: o2,    })

ref是一个函数又有什么益处?

  • 不便react销毁组件、从新渲染的时候去清空refs的货色,避免内存泄露