乐趣区

关于react.js:字节前端必会react面试题

React 中 keys 的作用是什么?

Keys 是 React 用于追踪哪些列表中元素被批改、被增加或者被移除的辅助标识。

在 React 中渲染汇合时,向每个反复的元素增加关键字对于帮忙 React 跟踪元素与数据之间的关联十分重要。key 应该是惟一 ID,最好是 UUID 或收集项中的其余惟一字符串:

<ul>
  {todos.map((todo) =>
    <li key={todo.id}>
      {todo.text}
    </li>
  )};
</ul>

在汇合中增加和删除我的项目时,不应用键或将索引用作键会导致奇怪的行为。

diff 算法?

  • 把树形构造依照层级合成,只比拟同级元素。
  • 给列表构造的每个单元增加惟一的 key 属性,不便比拟。
  • React 只会匹配雷同 classcomponent(这外面的 class 指的是组件的名字)
  • 合并操作,调用 componentsetState 办法的时候, React 将其标记为 – dirty. 到每一个事件循环完结, React 查看所有标记 dirtycomponent从新绘制.
  • 抉择性子树渲染。开发人员能够重写 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。

用户不同权限 能够查看不同的页面 如何实现?

  1. Js 形式
    依据用户权限类型,把菜单配置成 json, 没有权限的间接不显示
  2. 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);
         }
      }
    }}>
  1. 本人封装一个 privateRouter 组件 外面判断是否有权限,有的话返回
    <Route path={path} component={component} exact={exact}/>
    没有权限的话 component 返回一个提示信息的组件。
  2. 扩大一下,如果是依据用权限来判断是否暗藏组件该怎么做呢?
    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 — 很少应用。它能够用于代替组件的 componentWillReceivePropsshouldComponentUpdate(但不能拜访之前的 props)
  • componentDidUpdate — 罕用于更新 DOM,响应 prop 或 state 的扭转
  • componentWillUnmount — 在这你能够勾销网络申请,或者移除所有与组件相干的事件监听器

vue 或者 react 优化整体优化

  1. 虚构 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 更新流程: 这个过程当中波及的函数:

  1. shouldComponentUpdate: 当组件的 state 或 props 产生扭转时,都会首先触发这个生命周期函数。它会接管两个参数:nextProps, nextState——它们别离代表传入的新 props 和新的 state 值。拿到这两个值之后,咱们就能够通过一些比照逻辑来决定是否有 re-render(重渲染)的必要了。如果该函数的返回值为 false,则生命周期终止,反之持续;

留神:此办法仅作为 性能优化的形式 而存在。不要希图依附此办法来“阻止”渲染,因为这可能会产生 bug。应该 思考应用内置的 PureComponent 组件,而不是手动编写 shouldComponentUpdate()

  1. componentWillUpdate:当组件的 state 或 props 产生扭转时,会在渲染之前调用 componentWillUpdate。componentWillUpdate 是 React16 废除的三个生命周期之一。过来,咱们可能心愿能在这个阶段去收集一些必要的信息(比方更新前的 DOM 信息等等),当初咱们齐全能够在 React16 的 getSnapshotBeforeUpdate 中去做这些事;
  2. 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 来代替它。
退出移动版