React 中 keys 的作用是什么?
Keys 是 React 用于追踪哪些列表中元素被批改、被增加或者被移除的辅助标识。
在 React 中渲染汇合时,向每个反复的元素增加关键字对于帮忙React跟踪元素与数据之间的关联十分重要。key 应该是惟一ID,最好是 UUID 或收集项中的其余惟一字符串:
<ul> {todos.map((todo) => <li key={todo.id}> {todo.text} </li> )};</ul>
在汇合中增加和删除我的项目时,不应用键或将索引用作键会导致奇怪的行为。
diff算法?
- 把树形构造依照层级合成,只比拟同级元素。
- 给列表构造的每个单元增加惟一的
key
属性,不便比拟。 React
只会匹配雷同class
的component
(这外面的class
指的是组件的名字)- 合并操作,调用
component
的setState
办法的时候,React
将其标记为 -dirty
.到每一个事件循环完结,React
查看所有标记dirty
的component
从新绘制. - 抉择性子树渲染。开发人员能够重写
shouldComponentUpdate
进步diff
的性能
父子组件的通信形式?
父组件向子组件通信:父组件通过 props 向子组件传递须要的信息。
// 子组件: Childconst Child = props =>{ return <p>{props.name}</p>}// 父组件 Parentconst Parent = ()=>{ return <Child name="react"></Child>}
子组件向父组件通信:: props+回调的形式。
// 子组件: Childconst Child = props =>{ const cb = msg =>{ return ()=>{ props.callback(msg) } } return ( <button onClick={cb("你好!")}>你好</button> )}// 父组件 Parentclass Parent extends Component { callback(msg){ console.log(msg) } render(){ return <Child callback={this.callback.bind(this)}></Child> }}
React-Router的路由有几种模式?
React-Router 反对应用 hash(对应 HashRouter)和 browser(对应 BrowserRouter) 两种路由规定, react-router-dom 提供了 BrowserRouter 和 HashRouter 两个组件来实现利用的 UI 和 URL 同步:
- BrowserRouter 创立的 URL 格局:xxx.com/path
- HashRouter 创立的 URL 格局:xxx.com/#/path
(1)BrowserRouter
它应用 HTML5 提供的 history API(pushState、replaceState 和 popstate 事件)来放弃 UI 和 URL 的同步。由此能够看出,BrowserRouter 是应用 HTML 5 的 history API 来管制路由跳转的:
<BrowserRouter basename={string} forceRefresh={bool} getUserConfirmation={func} keyLength={number}/>
其中的属性如下:
- basename 所有路由的基准 URL。basename 的正确格局是后面有一个前导斜杠,但不能有尾部斜杠;
<BrowserRouter basename="/calendar"> <Link to="/today" /></BrowserRouter>
等同于
<a href="/calendar/today" />
- forceRefresh 如果为 true,在导航的过程中整个页面将会刷新。个别状况下,只有在不反对 HTML5 history API 的浏览器中应用此性能;
- getUserConfirmation 用于确认导航的函数,默认应用 window.confirm。例如,当从 /a 导航至 /b 时,会应用默认的 confirm 函数弹出一个提醒,用户点击确定后才进行导航,否则不做任何解决;
// 这是默认的确认函数const getConfirmation = (message, callback) => { const allowTransition = window.confirm(message); callback(allowTransition);}<BrowserRouter getUserConfirmation={getConfirmation} />
须要配合<Prompt>
一起应用。
- KeyLength 用来设置 Location.Key 的长度。
(2)HashRouter
应用 URL 的 hash 局部(即 window.location.hash)来放弃 UI 和 URL 的同步。由此能够看出,HashRouter 是通过 URL 的 hash 属性来管制路由跳转的:
<HashRouter basename={string} getUserConfirmation={func} hashType={string} />
其参数如下:
- basename, getUserConfirmation 和
BrowserRouter
性能一样; hashType window.location.hash 应用的 hash 类型,有如下几种:
- slash - 前面跟一个斜杠,例如 #/ 和 #/sunshine/lollipops;
- noslash - 前面没有斜杠,例如 # 和 #sunshine/lollipops;
- hashbang - Google 格调的 ajax crawlable,例如 #!/ 和 #!/sunshine/lollipops。
用户不同权限 能够查看不同的页面 如何实现?
- Js形式
依据用户权限类型,把菜单配置成json, 没有权限的间接不显示 - react-router 形式 在route 标签上 增加onEnter事件,进入路由之前替换到首页
<Route path="/home" component={App} onEnter={(nexState,replace)=>{ if(nexState.location.pathname!=='/'){ var sid = UtilsMoudle.getSidFromUrl(nexState); if(!sid){ replace("/") }else{ console.log(sid); } } }}>
- 本人封装一个privateRouter组件 外面判断是否有权限,有的话返回
<Route path={path} component={component} exact={exact}/>
没有权限的话component 返回一个提示信息的组件。 - 扩大一下,如果是依据用权限来判断是否暗藏组件该怎么做呢?
react 能够应用高阶组件,在高阶组件外面判断是否有权限,而后判断是否返回组件,无权限返回null
vue 能够应用自定义指令,如果没有权限移除组件
// 须要在入口处增加自定义权限指令v-auth,显示可操作组件Vue.directive('auth', { bind: function (el, binding, vnode) { // 用户权限表 const rules = auths for (let i = 0; i < rules.length; i++) { const item = rules[i] if(!binding.value || (binding.value == item.auth)){ // 权限容许则显示组件 return true } } // 移除组件 el.parentNode.removeChild(el) }})// 应用<template> <div> <Button v-auth="admin_user_add">增加用户</Button> <Button v-auth="admin_user_del">删除用户</Button> <Button v-auth="admin_user_edit">编辑用户</Button> </div></template>
对于store的了解
Store 就是把它们分割到一起的对象。Store 有以下职责:
- 维持利用的 state;
- 提供 getState() 办法获取 state;
- 提供 dispatch(action) 办法更新 state;
- 通过 subscribe(listener)注册监听器;
- 通过 subscribe(listener)返回的函数登记监听器
参考 前端进阶面试题具体解答
高阶组件
高阶函数:如果一个函数承受一个或多个函数作为参数或者返回一个函数就可称之为高阶函数。
高阶组件:如果一个函数 承受一个或多个组件作为参数并且返回一个组件 就可称之为 高阶组件。
react 中的高阶组件
React 中的高阶组件次要有两种模式:属性代理和反向继承。
属性代理 Proxy
- 操作
props
- 抽离
state
- 通过
ref
拜访到组件实例 - 用其余元素包裹传入的组件
WrappedComponent
反向继承
会发现其属性代理和反向继承的实现有些相似的中央,都是返回一个继承了某个父类的子类,只不过属性代理中继承的是 React.Component
,反向继承中继承的是传入的组件 WrappedComponent
。
反向继承能够用来做什么:
1.操作 state
高阶组件中能够读取、编辑和删除WrappedComponent
组件实例中的state
。甚至能够减少更多的state
项,然而十分不倡议这么做因为这可能会导致state
难以保护及治理。
function withLogging(WrappedComponent) { return class extends WrappedComponent { render() { return ( <div>; <h2>;Debugger Component Logging...<h2>; <p>;state:<p>; <pre>;{JSON.stringify(this.state, null, 4)}<pre>; <p>props:<p>; <pre>{JSON.stringify(this.props, null, 4)}<pre>; {super.render()} <div>; ); } }; }
2.渲染劫持(Render Highjacking)
条件渲染通过 props.isLoading 这个条件来判断渲染哪个组件。
批改由 render() 输入的 React 元素树
指出(组件)生命周期办法的不同
componentWillMount
-- 多用于根组件中的应用程序配置componentDidMount
-- 在这能够实现所有没有 DOM 就不能做的所有配置,并开始获取所有你须要的数据;如果须要设置事件监听,也能够在这实现componentWillReceiveProps
-- 这个周期函数作用于特定的 prop 扭转导致的 state 转换shouldComponentUpdate
-- 如果你放心组件适度渲染,shouldComponentUpdate
是一个改善性能的中央,因为如果组件接管了新的prop
, 它能够阻止(组件)从新渲染。shouldComponentUpdate 应该返回一个布尔值来决定组件是否要从新渲染componentWillUpdate
-- 很少应用。它能够用于代替组件的componentWillReceiveProps
和shouldComponentUpdate
(但不能拜访之前的 props)componentDidUpdate
-- 罕用于更新 DOM,响应 prop 或 state 的扭转componentWillUnmount
-- 在这你能够勾销网络申请,或者移除所有与组件相干的事件监听器
vue 或者react 优化整体优化
- 虚构dom
为什么虚构 dom 会进步性能?(必考)
虚构 dom 相当于在 js 和实在 dom 两头加了一个缓存,利用 dom diff 算法防止了没有必要的 dom 操作,从而进步性能。
用 JavaScript 对象构造示意 DOM 树的构造;而后用这个树构建一个真正的 DOM 树,插到文档当中当状态变更的时候,从新结构一棵新的对象树。而后用新的树和旧的树进行比拟,记录两棵树差别把 2 所记录的差别利用到步骤 1 所构建的真正的 DOM 树上,视图就更新了。
React组件的state和props有什么区别?
(1)props
props是一个从内部传进组件的参数,次要作为就是从父组件向子组件传递数据,它具备可读性和不变性,只能通过内部组件被动传入新的props来从新渲染子组件,否则子组件的props以及展示模式不会扭转。
(2)state
state的次要作用是用于组件保留、管制以及批改本人的状态,它只能在constructor中初始化,它算是组件的公有属性,不可通过内部拜访和批改,只能通过组件外部的this.setState来批改,批改state属性会导致组件的从新渲染。
(3)区别
- props 是传递给组件的(相似于函数的形参),而state 是在组件内被组件本人治理的(相似于在一个函数内申明的变量)。
- props 是不可批改的,所有 React 组件都必须像纯函数一样爱护它们的 props 不被更改。
- state 是在组件中创立的,个别在 constructor中初始化 state。state 是多变的、能够批改,每次setState都异步更新的。
React组件的构造函数有什么作用?它是必须的吗?
构造函数次要用于两个目标:
- 通过将对象调配给this.state来初始化本地状态
- 将事件处理程序办法绑定到实例上
所以,当在React class中须要设置state的初始值或者绑定事件时,须要加上构造函数,官网Demo:
class LikeButton extends React.Component { constructor() { super(); this.state = { liked: false }; this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState({liked: !this.state.liked}); } render() { const text = this.state.liked ? 'liked' : 'haven\'t liked'; return ( <div onClick={this.handleClick}> You {text} this. Click to toggle. </div> ); }}ReactDOM.render( <LikeButton />, document.getElementById('example'));
构造函数用来新建父类的this对象;子类必须在constructor办法中调用super办法;否则新建实例时会报错;因为子类没有本人的this对象,而是继承父类的this对象,而后对其进行加工。如果不调用super办法;子类就得不到this对象。
留神:
- constructor () 必须配上 super(), 如果要在constructor 外部应用 this.props 就要 传入props , 否则不必
- JavaScript中的 bind 每次都会返回一个新的函数, 为了性能等思考, 尽量在constructor中绑定事件
应用箭头函数(arrow functions)的长处是什么
- 作用域平安:在箭头函数之前,每一个新创建的函数都有定义本身的
this
值(在构造函数中是新对象;在严格模式下,函数调用中的this
是未定义的;如果函数被称为“对象办法”,则为根底对象等),但箭头函数不会,它会应用关闭执行上下文的this
值。 - 简略:箭头函数易于浏览和书写
- 清晰:当一切都是一个箭头函数,任何惯例函数都能够立刻用于定义作用域。开发者总是能够查找 next-higher 函数语句,以查看
this
的值
react 生命周期
初始化阶段:
- getDefaultProps:获取实例的默认属性
- getInitialState:获取每个实例的初始化状态
- componentWillMount:组件行将被装载、渲染到页面上
- render:组件在这里生成虚构的 DOM 节点
- componentDidMount:组件真正在被装载之后
运行中状态:
- componentWillReceiveProps:组件将要接管到属性的时候调用
- shouldComponentUpdate:组件承受到新属性或者新状态的时候(能够返回 false,接收数据后不更新,阻止 render 调用,前面的函数不会被继续执行了)
- componentWillUpdate:组件行将更新不能批改属性和状态
- render:组件从新描述
- componentDidUpdate:组件曾经更新
销毁阶段:
- componentWillUnmount:组件行将销毁
shouldComponentUpdate 是做什么的,(react 性能优化是哪个周期函数?)
shouldComponentUpdate 这个办法用来判断是否须要调用 render 办法从新描述 dom。因为 dom 的描述十分耗费性能,如果咱们能在 shouldComponentUpdate 办法中可能写出更优化的 dom diff 算法,能够极大的进步性能。
在react17 会删除以下三个生命周期
componentWillMount,componentWillReceiveProps , componentWillUpdate
Redux中的connect有什么作用
connect负责连贯React和Redux
(1)获取state
connect 通过 context获取 Provider 中的 store,通过 store.getState()
获取整个store tree 上所有state
(2)包装原组件
将state和action通过props的形式传入到原组件外部 wrapWithConnect 返回—个 ReactComponent 对 象 Connect,Connect 重 新 render 内部传入的原组件 WrappedComponent ,并把 connect 中传入的 mapStateToProps,mapDispatchToProps与组件上原有的 props合并后,通过属性的形式传给WrappedComponent
(3)监听store tree变动
connect缓存了store tree中state的状态,通过以后state状态 和变更前 state 状态进行比拟,从而确定是否调用 this.setState()
办法触发Connect及其子组件的从新渲染
React中的setState和replaceState的区别是什么?
(1)setState() setState()用于设置状态对象,其语法如下:
setState(object nextState[, function callback])
- nextState,将要设置的新状态,该状态会和以后的state合并
- callback,可选参数,回调函数。该函数会在setState设置胜利,且组件从新渲染后调用。
合并nextState和以后state,并从新渲染组件。setState是React事件处理函数中和申请回调函数中触发UI更新的次要办法。
(2)replaceState() replaceState()办法与setState()相似,然而办法只会保留nextState中状态,原state不在nextState中的状态都会被删除。其语法如下:
replaceState(object nextState[, function callback])
- nextState,将要设置的新状态,该状态会替换以后的state。
- callback,可选参数,回调函数。该函数会在replaceState设置胜利,且组件从新渲染后调用。
总结: setState 是批改其中的局部状态,相当于 Object.assign,只是笼罩,不会缩小原来的状态。而replaceState 是齐全替换原来的状态,相当于赋值,将原来的 state 替换为另一个对象,如果新状态属性缩小,那么 state 中就没有这个状态了。
为什么 useState 要应用数组而不是对象
useState 的用法:
const [count, setCount] = useState(0)
能够看到 useState 返回的是一个数组,那么为什么是返回数组而不是返回对象呢?
这里用到了解构赋值,所以先来看一下ES6 的解构赋值:
数组的解构赋值
const foo = [1, 2, 3];const [one, two, three] = foo;console.log(one); // 1console.log(two); // 2console.log(three); // 3
对象的解构赋值
const user = { id: 888, name: "xiaoxin"};const { id, name } = user;console.log(id); // 888console.log(name); // "xiaoxin"
看完这两个例子,答案应该就进去了:
- 如果 useState 返回的是数组,那么使用者能够对数组中的元素命名,代码看起来也比拟洁净
- 如果 useState 返回的是对象,在解构对象的时候必须要和 useState 外部实现返回的对象同名,想要应用屡次的话,必须得设置别名能力应用返回值
上面来看看如果 useState 返回对象的状况:
// 第一次应用const { state, setState } = useState(false);// 第二次应用const { state: counter, setState: setCounter } = useState(0)
这里能够看到,返回对象的应用形式还是挺麻烦的,更何况理论我的项目中会应用的更频繁。 总结:useState 返回的是 array 而不是 object 的起因就是为了升高应用的复杂度,返回数组的话能够间接依据程序解构,而返回对象的话要想应用屡次就须要定义别名了。
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 高阶组件是什么,和一般组件有什么区别,实用什么场景
官网解释∶
高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 本身不是 React API 的一部分,它是一种基于 React 的组合个性而造成的设计模式。
高阶组件(HOC)就是一个函数,且该函数承受一个组件作为参数,并返回一个新的组件,它只是一种组件的设计模式,这种设计模式是由react本身的组合性质必然产生的。咱们将它们称为纯组件,因为它们能够承受任何动静提供的子组件,但它们不会批改或复制其输出组件中的任何行为。
// hoc的定义function withSubscription(WrappedComponent, selectData) { return class extends React.Component { constructor(props) { super(props); this.state = { data: selectData(DataSource, props) }; } // 一些通用的逻辑解决 render() { // ... 并应用新数据渲染被包装的组件! return <WrappedComponent data={this.state.data} {...this.props} />; } };// 应用const BlogPostWithSubscription = withSubscription(BlogPost, (DataSource, props) => DataSource.getBlogPost(props.id));
1)HOC的优缺点
- 长处∶ 逻辑服用、不影响被包裹组件的外部逻辑。
- 毛病∶hoc传递给被包裹组件的props容易和被包裹后的组件重名,进而被笼罩
2)实用场景
- 代码复用,逻辑形象
- 渲染劫持
- State 形象和更改
- Props 更改
3)具体利用例子
- 权限管制: 利用高阶组件的 条件渲染 个性能够对页面进行权限管制,权限管制个别分为两个维度:页面级别和 页面元素级别
// HOC.jsfunction withAdminAuth(WrappedComponent) { return class extends React.Component { state = { isAdmin: false, } async UNSAFE_componentWillMount() { const currentRole = await getCurrentUserRole(); this.setState({ isAdmin: currentRole === 'Admin', }); } render() { if (this.state.isAdmin) { return <WrappedComponent {...this.props} />; } else { return (<div>您没有权限查看该页面,请分割管理员!</div>); } } };}// pages/page-a.jsclass PageA extends React.Component { constructor(props) { super(props); // something here... } UNSAFE_componentWillMount() { // fetching data } render() { // render page with data }}export default withAdminAuth(PageA);// pages/page-b.jsclass PageB extends React.Component { constructor(props) { super(props); // something here... } UNSAFE_componentWillMount() { // fetching data } render() { // render page with data }}export default withAdminAuth(PageB);
- 组件渲染性能追踪: 借助父组件子组件生命周期规定捕捉子组件的生命周期,能够不便的对某个组件的渲染工夫进行记录∶
class Home extends React.Component { render() { return (<h1>Hello World.</h1>); } } function withTiming(WrappedComponent) { return class extends WrappedComponent { constructor(props) { super(props); this.start = 0; this.end = 0; } UNSAFE_componentWillMount() { super.componentWillMount && super.componentWillMount(); this.start = Date.now(); } componentDidMount() { super.componentDidMount && super.componentDidMount(); this.end = Date.now(); console.log(`${WrappedComponent.name} 组件渲染工夫为 ${this.end - this.start} ms`); } render() { return super.render(); } }; } export default withTiming(Home);
留神:withTiming 是利用 反向继承 实现的一个高阶组件,性能是计算被包裹组件(这里是 Home 组件)的渲染工夫。
- 页面复用
const withFetching = fetching => WrappedComponent => { return class extends React.Component { state = { data: [], } async UNSAFE_componentWillMount() { const data = await fetching(); this.setState({ data, }); } render() { return <WrappedComponent data={this.state.data} {...this.props} />; } }}// pages/page-a.jsexport default withFetching(fetching('science-fiction'))(MovieList);// pages/page-b.jsexport default withFetching(fetching('action'))(MovieList);// pages/page-other.jsexport default withFetching(fetching('some-other-type'))(MovieList);
辨别状态和 props
条件 | State | Props |
---|---|---|
1. 从父组件中接管初始值 | Yes | Yes |
2. 父组件能够扭转值 | No | Yes |
3. 在组件中设置默认值 | Yes | Yes |
4. 在组件的外部变动 | Yes | No |
5. 设置子组件的初始值 | Yes | Yes |
6. 在子组件的外部更改 | No | Yes |
state 和 props 触发更新的生命周期别离有什么区别?
state 更新流程: 这个过程当中波及的函数:
- shouldComponentUpdate: 当组件的 state 或 props 产生扭转时,都会首先触发这个生命周期函数。它会接管两个参数:nextProps, nextState——它们别离代表传入的新 props 和新的 state 值。拿到这两个值之后,咱们就能够通过一些比照逻辑来决定是否有 re-render(重渲染)的必要了。如果该函数的返回值为 false,则生命周期终止,反之持续;
留神:此办法仅作为性能优化的形式而存在。不要希图依附此办法来“阻止”渲染,因为这可能会产生 bug。应该思考应用内置的 PureComponent 组件,而不是手动编写 shouldComponentUpdate()
- componentWillUpdate:当组件的 state 或 props 产生扭转时,会在渲染之前调用 componentWillUpdate。componentWillUpdate 是 React16 废除的三个生命周期之一。过来,咱们可能心愿能在这个阶段去收集一些必要的信息(比方更新前的 DOM 信息等等),当初咱们齐全能够在 React16 的 getSnapshotBeforeUpdate 中去做这些事;
- componentDidUpdate:componentDidUpdate() 会在UI更新后会被立刻调用。它接管 prevProps(上一次的 props 值)作为入参,也就是说在此处咱们依然能够进行 props 值比照(再次阐明 componentWillUpdate 的确鸡肋哈)。
props 更新流程: 绝对于 state 更新,props 更新后惟一的区别是减少了对 componentWillReceiveProps 的调用。对于 componentWillReceiveProps,须要晓得这些事件:
- componentWillReceiveProps:它在Component承受到新的 props 时被触发。componentWillReceiveProps 会接管一个名为 nextProps 的参数(对应新的 props 值)。该生命周期是 React16 废除掉的三个生命周期之一。在它被废除前,能够用它来比拟 this.props 和 nextProps 来从新setState。在 React16 中,用一个相似的新生命周期 getDerivedStateFromProps 来代替它。