脚本宝典收集整理的这篇文章主要介绍了【知识总结】前端高频React面试题合集,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
keys是react用于追踪哪些元素被修改、 被添加、被移除的辅助标示。
render(){
return(
<ul>
{
this.state.list.map(({ITem,key})=>{
return <li key={key}> {item} </li>
})
}
</ul>
)
}
在开发过程中,我们需要保证某个元素的key在其同级元素中具有唯一性。
在react diff算法中react会借助元素的key来判断元素是新创建的还是被移动而来的元素,从而减少不必要的元素重新渲染。此外,react还需要借助key值来判断元素与本地状态的关联关系,因此我们绝不可忽视转换函数中key的重要性。
将传递给setState的对象合并到组件的当前状态,这将启动一个和解的过程,构建一个新的react元素树,与上一个元素树进行对比(diff),进而最小化的重渲染。
因为this.PRops
和this.state
的更新是异步的,不能依赖它们的值去计算下一个state
在React组件中,应该在componentDidmount中发起网络请求。这个方法会在组件第一次“挂载”时执行,在组件的生命周期中仅会执行一次。
更重要的是,不能保证在组件挂载之间Ajax请求已经完成,如果是这样,也就以为在将尝试在一个为挂载的组件上调用setState,这不会起任何作用。
所有在componentDidMount中发起网络请求就保证了这一个组件可以更新了。
React.createClass() 、ES6 Class 、无状态函数
Refs是<span></span>
React提供给我们的安全访问DOM元素或者某个组件实例的句柄。 我们可以为元素添加ref属性,然后在回调函数中接受该元素在DOM树中的句柄,该值会作为回调函数的第一个参数返回F1a;
class CustomForm extends Component{
handleSubmit = () => {
console.LOG('Input Value: ',this.input.value);
};
render(){
return(
<form onSubmit={this.handleSubmit}>
<input tyPE='text' ref={input=> (this.input = input)}/>
<button type='submit'> Submit </button>
</form>
)
}
}
上面例子中input包含了一个ref属性,该属性声明的回调函数会接收input对应的DOM元素,我们将其绑定到指定this指针以便在其他的类函数中使用。
把树形结构按层级分解,只比较同级元素。
给列表结构的每一个单元添加唯一的key属性,方便比较。
react只会匹配相同的class的component合并操作,调用component的setState的时候,react将其标记为dirty,到每一个事件循环结束,react检查所有标记dirty的component重新绘制,选择性子树渲染。
开发人员可以重写shouldComponentUpdate提高diff的性能。
call、apply、bind指的是this上谁就是谁
this的情况:
promise是解决回调地狱的好工具,比起直接使用回调函数promise的语法更加清晰,代码的可读性大大增加。
老旧浏览器没有promise全局对象怎么办?
可以使用es6-promise-polyfill
,可以使用页面标签直接引入,也可以使用es6的import方法引入。引入之后,它就会在window对象中加入promise对象,这样我们就可以全局使用promise了。
如何进行异常处理?
参照promise的文档,我们可以在reject回调和catch中处理异常。但promise规定如果一个错误在reject函数中被处理,那么promise将从异常常态中恢复过来。这意味着接下来的then方法将接收一个resolve回调。
大多数时候我们希望发生错误的时候,promise处理当前的异常并中断后续的then操作。我们先来看一个使用reject处理异常的例子:
VAR promiseStart = new Promise(function(resolve, reject){
reject('promise is rejected');
});
promiseStart.then(function(response){
console.log('resolved');
return new Promise(function(resolve,reject){
resolve('promise is resolved');
});
})
.then(function(response){
console.log('resolved:',response);
})
.catch(function(error){
console.log('catched:',error);
})
输出: catched: promise is resolved
数据传递
在react中,父组件给子组件传递数据时,通过给子组件设置props的方式,子组件取得props中的值,即可完成数据传递。被传递数据的格式是可以是任何js可识别的数据结构。
数据改变
props不能被自身修改,如果组件内部的属性发生变化使用state。
react会实时监听每个组件的props和state的值,一旦有变化,会立刻更新组件,将结果重新渲染到页面上。
react渲染性能优化的三个方向:
核心是利用Blob.prototype.slice
方法,它和数组的slice方法相似,调用的slice方法可以返回原文件的某个切片。
这样我们就可以根据预先设置好的切片最大数量将文件切分为一个个切片,然后借助http的可并发性,同时上传多个切片,这样从原文传一个大文件,变成了同时传多个小的文件切片,可以大大减少上传时间。
另外由于是并发,传输到服务器的顺序可能会发现变化,所有我们还需要给每个切片记录顺序。
使用异步promise ALL 或者web wroker
主要作用:把所有的state集中到组件顶部,能够灵活的将所有的state各取所需的分发给所有的组件。
父传子
父组件向子组件通过props的方式,向子组件进行通信。
子传父
props + 回调的方式,父组件向子组件传递props进行通讯,此props的作用与为父组件自身的函数,子组件调用该函数,将子组件要传递的信息作为参数传递到父组件的作用域中。
兄弟间
找到这两个兄弟节点共同的父节点,结合上面两种方式,由父组件转发信息进行通信。
跨层级通信
context设计目的是为了共享哪些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题、首选语言,对于跨越多层的全局数据通过context通信再合适不过。
const StateContext = React.createContext()
class Parent extends React.Component{
render(
return(
<StateContext.Provider value='hello'> //value就是传入Context的值
<Child/>
</StateContext.Provider>
)
)
}
class Child extends React.Component{
render(){
return(
<ThemeContext.Consumer>
{
context=>(
name is {context} //取出值
)
}
</ThemeContext.Consumer>
);
}
}
发布订阅模式
发布者发布事件,订阅者监听事件并做出反应,我们可以通过引入event模块进行通信。
全局状态管理工具
借助redux 或者 Mobx等全局状态管理工具进行通信,这种工具会维护一个全局状态中心Store,并根据不同的事件产生新的状态。
当然,我们可以在componentDidmount中直接进行请求无需借助redux。
但在一定规模的项目中,上述方法很难进行异步流的管理,通常情况下我们会借助redux的异步中间件进行异步处理。
redux的异步流中间件其实又很多,当下主流的异步中间件只有两种:redux-thunk、redux-saga,当然redux-observable可能也有资格占据一席之地。
抛开已被官方弃用的Mixin,组件抽象的技术目前有三种比较主流:
1)高阶组件
高阶组件是react中服用逻辑的一种高级技巧。简而言之,高阶组件就是一个函数,它接受一个组件为参数,返回一个新的组件。
高阶组件定义:
function HocComponent(WrappedComponent){
return class ProxyComponent extends React.Component{
render(){
return <WrappedComponent {...this.props}>
}
}
}
高阶组件约定:
高阶组件注意事项:
高阶组件的缺点:
2)渲染属性(render props)
render props 是一个用于告知组件渲染什么内容的函数属性。该函数返回一个组件,是渲染出来的内容。
作用是为了功能的复用,与HOC类似;其次是组件间的数据单项传递。
相对于高阶组件的优点:
3)Hooks(推荐使用)
在一个函数中定义的state,可以直接拿到另一个函数中使用,有了hooks,这种看似不可能的语法确实行得通。hook的优势不仅体现在代码量上,从风格上来说,也显得语义更清晰、结构更优雅。
更重要的是,上述两种模式的种种缺点,它一个都没有
Virtual DOM是一个轻量级的JavaScript对象,它最初是real DOM的副本。它是一个节点树,将元素、属性、内容作为对象及其属性。
react的渲染函数从react组件中创建一个节点树。然后它响应数据模型的变化来更新树,该变化是由用户或系统完成的各种动作引起的。
Virtual DOM有三个简单的步骤:
reducers是纯函数,它规定应用程序的状态怎样因响应Action而变化。reducer通过接受先前的状态和action来工作,然后它返回一个新的状态。它根据操作的类型确定需要执行哪种更新,然后返回新的值。如果不需要完成任务,它会返回原来的状态。
当你想要仅显示要在多个定义的路由中呈现单个路由时,可以使用switch关键字。它会按顺序将已定义的URL与已定义的路由进行匹配,找到第一个匹配项后,它将渲染指定的路径,从而绕过其他路线。
<BrowserRouter>
组件中。可以使用属性初始值设定项property initializers
来正确绑定回调,create-react-app
也是默认支持的。
通常情况下,我们会使用Webpack和definePlugin方法来将NODE_env变量值设置为production。
编译版本中react忽略了propType验证以及其他的告警信息,同时还会降低代码库的大小,react是用来Uglify插件来移除生产环境下不必要的注释等信息。
shouldComponentUpdate允许我们手动的判断是否要进行组件更新根据组件的应用设置函数的合理返回值能够帮我们避免不必要的更新。
createElement函数是JSX编译之后使用的创建的函数。
cloneElement是用于复制某个元素并传入新的props。
中间件提供第三方插件的模式自定义拦截:
action -> reducer
的过程变为action -> middlewares -> reducer
这种机制可以让我们改变数据流实现异步action
一个组件所需要的数据必须由父组件传递过来。
当一个组件相关数据更新时即使父组件不需要用到这个组件,父组件还是会从重新render可能有效率影响或者要写更复杂的shouldComponentUpdate进行判断。
在以前react中所有的组件都会位于#app 下而使用Portals提供了一种脱离#app的组件,因此Portals适合脱离文档流的组件特别是:position:absolute
与 position:fixed
的组件。
useEffect可以看成是componentDidMound、componentDidupdate、componentWillUnmount三者的结合。
useEffect(callback, [source])接受两个参数的调用方式如下:
useEffect(()=>{
console.log(';mounted');
return ()=>{
console.log('willUnmount');
}
},[source]);
生命周期函数的调用主要是通过第二个参数[source]来进行控制有如下几个情况:
shouldComponentUpdate
钩子对新旧props进行比较,如果值相同则阻止更新,避免不必要的渲染,或者使用PureReactComponent
替代Component其内部已经封装来shouldComponentUpdate
的浅比较逻辑。webpack-bundle-analyzer
分析当前页面的依赖包是否存在不合理性,如果存在着到并进行优化。在React Hooks中useEffect可以看作是componentDidMount
、componentDidUpdate
、componentWillUnmount
的结合。
通过第二个参数我们便可以模拟出几个常用的生命周期:
const useMounted = () => {
const [mounted,setMounted] = useState(false);
useEffect(()=>{
!mounted && setMounted(true);
return ()=> setMounted(false);
},[]);
return mounted;
}
componentDidUpdate: useEffect每次均会执行其实就是排除了DidMount后即可
const mounted = useMounted()
useEffect (()=>{
mounted && fn()
})
其他内置钩子:
pureComponent和component完全相同。
但是在shouldComponentUpdate实现中pureComponent使用了props和state浅比较。
主要作用是用来提高某些特定场景的性能。
为什么用redux
在react中数据在组件中是单向流动的,数据从一个方向父组件流向子组件通过props,所有两个非父组件间通信相对麻烦,redux的出现就是为了解决state里面的数据问题
redux设计理念
redux是将整个应用状态存储到一个地方称为store,里面保存着一个状态树store tree, 组件可以派发dispatch行为给store,而不是直接通知其他组件,组件内部通过订阅store中的状态state来刷新自己的视图。
redux的三大原则
首先connect之所以会成功是因为Provider组件,在原应用组件上包裹一层使原来整个应用成为Provider的子组件。接收redux的store作为props通过context对象传递给子孙组件上的connect。
connect上一个高阶函数,首先传入mapStateToProps、mapDispatchToProps,然后返回一个生产component的函数,再将真正的component作为参数传入wrapWithConnect,这样就生产出一个经过包裹的connect组件,该组件具有如下特点:
通常我们输出节点的时候都是map一个数组,然后返回一个ReactNode,为了方便内部进行优化,我们必须给每一个ReactNode添加key,这个key prop再设计值处不是给开发者用的,而是给react用的,大概的作用就是给每一个ReactNode添加一个身份标识,以方便react进行识别在重渲染过程中如果key一样,若有组件属性变化,则react只更新组件对于的属性;反之若无属性变化,则不更新;如果key不一样则react先销毁组件然后重新创建该组件。
<Link>
标签和<a>
标签有什么区别react-router
是伴随着react框架出现的路有系统,它也是公认的一种优秀的路有解决方案。
在使用react-router时候,我们常常会使用其自带的路径跳转组件Link实现,对比a标签,Link组件避免了不必要的重渲染。
有时候表现出异步,有时候表现出同步
<span></span>
production版的react.js该函数会在setState函数调用完成并且组件开始重渲染的时候调用,我们可以用该函数来监听渲染是否完成:
this.setState(
{username:'heiheihe'},
()=> console.log('setState has finished and the component has re-rendered')
)
this.setState((prevState,props)=>{
return{
streak:prevState.streak + props.count
}
})
shouldComponentUpdate
这个方法来判断是否需要调用render方法来重新描绘dom。因为dom的描绘非常消耗性能。
以上是脚本宝典为你收集整理的【知识总结】前端高频React面试题合集全部内容,希望文章能够帮你解决【知识总结】前端高频React面试题合集所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。