等。此函数必须是纯函数,即每次都必须返回相同的结果叫做。React中constructor和getInitialState的区别?两者都用于初始化状态。前者是ES6中的语法,后者是ES5中的语法。这个方法在新版本的React中已经被弃用了。getInitialState是ES5中的一个方法。如果使用createClass方法创建一个Component组件,可以自动调用其getInitialState方法获取初始化的State对象。varAPP=React.creatClass({getInitialState(){return{userName:'hi',userId:0}; }})React去掉了ES6实现中的getInitialState钩子函数,规定state在ES6实现中构造器,如下:ClassAppextendsReact.Component{constructor(props){super(props);this.state={};}}对React-Fiber的理解,它解决了什么问题?ReactV15在渲染时,会递归比较VirtualDOM树,找出需要更改的节点,然后同步更新,一气呵成。在这个过程中,React会占用浏览器资源,导致用户触发的事件无响应,并导致掉帧,让用户有卡顿的感觉。为了给用户造成应用很快的“假象”,不能让一个任务长时间占用资源。浏览器的渲染、布局、绘制、资源加载(如HTML解析)、事件响应、脚本执行等都可以看作是操作系统的“进程”,需要通过一定的调度策略合理分配CPU资源,以提高浏览器性能。用户响应率,同时兼顾任务执行效率。所以React使用Fiber架构让这个执行过程可以中断。“及时”放弃CPU执行权,不仅可以让浏览器及时响应用户交互,还有其他好处:批量操作DOM并延迟操作,避免操作大量DOM一次结点,获得更好的用户体验;给浏览器一点喘息的空间,它会编译和优化代码(JIT)并进行热代码优化,或纠正回流。核心思想:Fiber也叫coroutine或者fiber。它与线程不同。协程本身没有并发或并行能力(需要和线程配合)。它只是一种放弃控制过程的机制。放弃CPU的执行权,让CPU在这段时间内可以进行其他的操作。渲染过程可以被中断,将控制权交还给浏览器让位于高优先级的任务,并在浏览器空闲后恢复渲染。在React中,什么是stateState类似于props,但是它是私有的,完全由组件自己控制。State本质上是一个对象,它保存数据并决定组件如何呈现。React.Component和React.PureComponent的区别PureComponent代表一个纯组件,可以用来优化React程序,减少render函数的执行次数,从而提高组件的性能。在React中,当prop或state发生变化时,可以通过在shouldComponentUpdate生命周期函数中执行returnfalse来阻止页面的更新,从而减少不必要的render执行。React.PureComponent会自动实现shouldComponentUpdate。而pureComponent中的shouldComponentUpdate()进行的是浅层比较,也就是说如果是引用数据类型的数据,只会比较是否不是同一个地址,不会比较这个地址中的数据是否是持续的。浅比较忽略属性和/或状态突变。实际上,数据引用指针并没有发生变化,数据发生变化时re??nder也不会被执行。如果需要重新渲染,需要重新打开空间参考数据。PureComponent一般用在一些纯显示组件上。使用pureComponent的好处:当组件更新时,如果组件的props或state没有发生变化,则不会触发render函数。省略了虚拟DOM的生成和比较过程,以达到提升性能的目的。这是因为React会自动进行浅比较。除了在构造函数中绑定this之外,还有其他方法吗?您可以使用属性初始化器来正确绑定回调,默认情况下create-react-app也支持。在回调中你可以使用箭头函数,但问题是每次组件渲染时都会创建一个新的回调。调用setState后会发生什么,详见前端进阶面试题。在代码中调用setState函数后,React会将传入的参数与之前的状态合并,然后触发所谓的调和过程(Reconciliation)。在协调过程之后,React将以一种相对高效的方式根据新的状态构建React元素树,并开始重新渲染整个UI界面。React拿到元素树后,React会计算新旧树的差异,然后根据差异最小化并重新渲染界面。通过diff算法,React可以准确地指导哪些位置发生了变化以及应该如何变化,从而确保按需更新而不是完全重新渲染。setState时,React会为当前节点创建一个updateQueue的更新队列。然后将触发对帐过程。在此过程中,将使用一种称为Fiber的调度算法开始生成新的Fiber树。Fiber算法最大的特点就是可以异步、可中断地执行。然后ReactScheduler会根据优先级优先执行优先级高的节点,具体执行doWork方法。在doWork方法中,React会执行updateQueue中的方法获取新的节点。然后比较新旧节点,并用更新、插入和替换标记旧节点。当前节点的doWork完成后,会执行performUnitOfWork方法获取新的节点,然后重复上述过程。当所有节点都完成doWork后,会触发commitRoot方法,React进入commit阶段。在commit阶段,React会为每个节点根据之前的Tag一次性更新整个dom元素。react-redux是如何工作的?通过redux和reactcontext的使用,借助高阶函数,react-reduxreact中的Portal是什么?门户提供了一种很好的方式来将子节点呈现给DOM节点而不是父组件。第一个参数(child)是任何可渲染的React子元素,例如元素、字符串或片段。第二个参数(容器)是一个DOM元素。ReactDOM.createPortal(child,container)讲述了React组件开发中作用域的常见问题。在EMAScript5语法规范中,关于作用域的常见问题如下。(1)在map等方法的回调函数中,必须绑定this的作用域(通过bind方法)。(2)父组件传递给子组件的方法作用域是父组件的实例化对象,不能改变。(3)组件事件回调函数方法的作用域为组件实例化对象(绑定父组件提供的方法为父组件实例化对象),不可更改。在EMAScript6语法规范中,关于作用域的常见问题如下。(1)当使用箭头函数作为map等方法的回调函数时,箭头函数的作用域为当前组件的实例化对象(即箭头函数的作用域为定义的作用域),并且不需要绑定范围。(2)事件回调函数必须绑定到组件作用域。(3)父组件的传递方法必须绑定父组件的作用域。简而言之,在EMAScript6语法规范中,组件方法的范围是可以改变的。Component、Element、Instance有什么区别和联系?元素:元素元素是一个普通对象,描述了您希望它如何出现在DOM节点或其他组件组件的屏幕上。element元素可以在其props中包含其他元素。创建一个React元素很便宜。元素在创建后是不可变的。Component:组件组件可以通过多种方式声明。它可以是一个带有render()方法的类,或者简单地定义为一个函数。在这两种情况下,它都将props作为输入并返回一棵元素树作为输出。Instance:实例实例就是你在你写的组件类中使用关键字this指向的东西(译注:ComponentInstance)。它对于存储本地状态和响应生命周期事件很有用。功能组件根本没有实例。类组件(Classcomponents)有实例,但你永远不需要直接创建一个组件的实例,因为React帮我们做了。为什么使用React.Children.map(props.children,()=>)而不是props.children.map(()=>)?因为不能保证props.children会是一个数组。以下面的代码为例。
Thereareclassfront-endnetwork
在父组件内部,如果尝试使用props.children.map映射子对象,会抛出错误,因为props.children是一个对象,而不是数组。如果有多个孩子,React会将props.children变成一个如下所示的数组。
优客前端网
前端技术学习平台
;//不建议使用下面的方法,会报错在这种情况下抛出。classParentextendsComponent{render(){return
{this.props.children.map((obj)=>obj)}
;}}推荐使用下面的方法,避免抛出前面case的错误。classParentextendsComponent{render(){return
{React.Children.map(this.props.children,(obj)=>obj)}
;}}什么是JSX表达式中的Children,开始标记(如
)和结束标记(如)之间的内容会作为特殊属性props.children自动传递给包含组件。这个属性有很多可用的方法,包括React.Children.map、React.Children.forEach、React.Children.count、React.Children.only、React.Children.toArray。简述React事件机制当用户添加onClick的功能时,React并没有将Click时间绑定到DOM上,而是监听文档处所有支持的事件。当事件发生冒泡到文档时,React会将事件的内容封装交给中间层SyntheticEvent(负责所有的事件合成),所以当事件触发时,会使用统一的分发函数dispatchEvent来执行指定的函数。React在自己的合成事件中重写了stopPropagation方法,将isPropagationStopped设置为true,然后在每一级事件的遍历过程中,根据这个遍历判断是否继续执行。这是React自己实现的冒泡机制。在React实现的移动应用中,如果出现卡顿,可以考虑哪些优化方案?添加shouldComponentUpdate钩子来比较新旧道具。如果值相同,则阻止更新以避免不必要的渲染。或者使用PureReactComponent代替Component,Component已经封装了shouldComponentUpdate的浅层比较逻辑。对于列表或其他具有相同结构的节点,为每一项添加一个唯一的key属性,以方便React的diff算法中节点的复用。减少节点的创建和删除。减少render函数中onClick={()=>{doSomething()}}的写法。每次调用render函数都会创建一个新函数,即使内容没有改变。这将导致不必要的节点重新渲染。建议将函数保存在组件的成员对象中,这样组件的props只会被创建一次。如果需要经过一系列的计算得到最终的结果,可以考虑使用reselect库对结果进行Cache处理,如果props的值没有变化,会直接从缓存中取结果,避免high计算成本。webpack-bundle-analyzer分析当前页面的依赖包,是否有不合理之处,如果有,找到优化点,优化Reactrefs的作用是什么Refs是React为我们提供安全访问DOM元素的句柄或组件实例。您可以为元素添加一个ref属性,然后在回调函数中接受DOM树中元素的句柄。该值将作为回调函数的第一个参数返回,不同权限的用户可以查看不同的页面。如何实现?Js方法根据用户权限类型将菜单配置为json,react-router方法不会根据用户权限类型直接显示菜单。react-router方法在路由标签中添加onEnter事件,并在进入路由前将其替换为首页。
{if(nexState.location.pathname!=='/'){varsid=UtilsMoudle.getSidFromUrl(nexState);如果(!sid){替换("/")}else{console.log(sid);}}}}>封装一个privateRouter组件,判断是否有权限,返回如果没有权限,组件返回一个提示信息的组件拓展一下,如果我们根据权限判断是否隐藏组件怎么办?React可以使用高级组件,判断高级组件中是否有权限,然后判断是否返回组件,没有权限则返回nullVue可以使用自定义指令,如果没有权限则移除组件//需要在入口添加自定义权限指令v-auth,显示可操作组件Vue.directive('auth',{bind:function(el,binding,vnode){//用户权限表construles=authsfor(leti=0;i添加用户删除用户编辑用户
有React数据持久化的实践吗?封装数据持久化组件:letstorage={//添加set(key,value){localStorage.setItem(key,JSON.stringify(value));},//获取获取(键){返回JSON.parse(localStorage.getItem(key));},//删除remove(key){localStorage.removeItem(key);}};导出默认存储;在React项目中,通过redux存储全局数据时,会出现一个问题,如果用户刷新网页,那么redux存储的所有全局数据都会被清空,比如登录信息等,此时会出现需要持久存储全局数据。首先想到的是localStorage。localStorage是一个没有时间限制的数据存储,可以用来实现数据的持久化存储。但是,在使用redux管理和存储全局数据的基础上,再使用localStorage读写数据,这样不仅工作量巨大,而且容易出错。那么有没有结合redux实现持久化数据存储的框架呢?当然是redux-persist。redux-persist会将reduxstore中的数据缓存到浏览器的localStorage中。它的使用步骤如下:(1)首先安装redux-persist:npmiredux-persist(2)reducer和action的处理不变,只是修改store的生成代码,如下:import{createStore}from'redux'从'../reducers/index'导入reducer'从'redux-persist'导入{persistStore,persistReducer};从'redux-persist/lib/storage'导入存储;从'redux-persist/lib/导入autoMergeLevel2stateReconciler/autoMergeLevel2';constpersistConfig={key:'root',storage:storage,stateReconciler:autoMergeLevel2//检查'MergeProcess'部分的详细信息};constmyPersistReducer=persistReducer(persistConfig,reducers)conststore=createStore(myPersistReducer)exportconstpersistor=persistStore(store)exportdefaultstore(3)在index.js中,使用PersistGate标签作为网页内容的父标签:importReact来自“反应”;从'react-dom'导入ReactDOM;从'react-redux'导入{Provider}从'./redux/store/store'导入存储从'./redux/store/store'导入{persistor}从'redux-persist/lib/integration/导入{PersistGate}反应';ReactDOM。渲染({/*网页内容*/},document.getElementById('root'));这样为了通过redux-persist实现React持久化本地数据存储的简单应用,应该在生命周期的哪一步发起AJAX请求呢?我们应该将AJAX请求放入componentDidMount函数中执行。主要原因是React的下一代协调算法Fiber会通过启动或停止渲染来优化应用程序性能,这会影响componentWillMount的触发次数。componentWillMount生命周期函数的调用次数会变得不确定,React可能会频繁调用componentWillMount多次。如果我们把AJAX请求放在componentWillMount函数中,显然会被多次触发,不是一个好的选择。如果我们将AJAX请求放在生命周期的其他函数中,我们不能保证该请求只会在组件挂载后请求响应。如果我们的数据请求在组件挂载之前完成,调用setState函数将数据添加到组件状态,对于未挂载的组件会报错。而在componentDidMount函数中执行AJAX请求可以有效避免这个问题。React提升应用性能有哪些优势?在客户端和服务端使用jsx模板进行数据渲染很方便,可读性好。