diff算法是怎么运作
每一种节点类型有本人的属性,也就是prop,每次进行diff的时候,react会先比拟该节点类型,如果节点类型不一样,那么react会间接删除该节点,而后间接创立新的节点插入到其中,如果节点类型一样,那么会比拟prop是否有更新,如果有prop不一样,那么react会断定该节点有更新,那么重渲染该节点,而后在对其子节点进行比拟,一层一层往下,直到没有子节点
react和vue的区别
相同点:
- 数据驱动页面,提供响应式的试图组件
- 都有virtual DOM,组件化的开发,通过props参数进行父子之间组件传递数据,都实现了webComponents标准
- 数据流动单向,都反对服务器的渲染SSR
- 都有反对native的办法,react有React native, vue有wexx
不同点:
- 数据绑定:Vue实现了双向的数据绑定,react数据流动是单向的
- 数据渲染:大规模的数据渲染,react更快
- 应用场景:React配合Redux架构适宜大规模多人合作简单我的项目,Vue适宜小快的我的项目
- 开发格调: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
中不会批量更新,在“异步”中如果对同一个值进行屡次setState
,setState
的批量更新策略会对其进行笼罩,取最初一次的执行,如果是同时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} /> } }}
- 提取状态: 能够通过 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()
。传递 props
给 super()
的起因则是便于(在子类中)能在 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的货色,避免内存泄露