共计 15647 个字符,预计需要花费 40 分钟才能阅读完成。
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 向子组件传递须要的信息。
// 子组件: Child
const Child = props =>{return <p>{props.name}</p>
}
// 父组件 Parent
const Parent = ()=>{return <Child name="react"></Child>}
子组件向父组件通信:: props+ 回调的形式。
// 子组件: Child
const Child = props =>{
const cb = msg =>{return ()=>{props.callback(msg)
}
}
return (<button onClick={cb("你好!")}> 你好 </button>
)
}
// 父组件 Parent
class 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); // 1
console.log(two); // 2
console.log(three); // 3
对象的解构赋值
const user = {
id: 888,
name: "xiaoxin"
};
const {id, name} = user;
console.log(id); // 888
console.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.js
function 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.js
class 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.js
class 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.js
export default withFetching(fetching('science-fiction'))(MovieList);
// pages/page-b.js
export default withFetching(fetching('action'))(MovieList);
// pages/page-other.js
export 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 来代替它。