总结
至此咱们介绍了react的理念,如果解决cpu和io的瓶颈,要害是实现异步可中断的更新
咱们介绍了react源码架构(ui=fn(state)),从scheduler开始调度(依据过期事件判断优先级),通过render阶段的深度优先遍历造成effectList(两头会执行reconcile|diff),交给commit解决实在节点(两头交叉生命周期和局部hooks),而这些调度的过程都离不开Fiber的撑持,Fiber是工作单元,也是节点优先级、更新UpdateQueue、节点信息的载体,Fiber双缓存则提供了比照前后节点更新的根底。咱们还介绍了jsx是React.createElement的语法糖。Lane模型则提供了更细粒度的优先级比照和计算,这所有都为concurrent mode提供了根底,在这之上变能够实现Suspense和batchedUpdate(16、17版本实现的逻辑不一样),18章context的valueStack和valueCursor在整个架构中运行机制,19章介绍了新版事件零碎,包含事件生产、监听和触发,
面试题简答(详见视频源码角度解说)
jsx和Fiber有什么关系
答:mount时通过jsx对象(调用createElement的后果)调用createFiberFromElement生成Fiber
update时通过reconcileChildFibers或reconcileChildrenArray比照新jsx和老的Fiber(current Fiber)生成新的wip Fiber树react17之前jsx文件为什么要申明import React from 'react',之后为什么不须要了
答:jsx通过编译之后编程React.createElement,不引入React就会报错,react17扭转了编译形式,变成了jsx.createElement
function App() { return <h1>Hello World</h1>;}//转换后import {jsx as _jsx} from 'react/jsx-runtime';function App() { return _jsx('h1', { children: 'Hello world' });}
Fiber是什么,它为什么能进步性能
答:Fiber是一个js对象,能承载节点信息、优先级、updateQueue,同时它还是一个工作单元。
- Fiber双缓存能够在构建好wip Fiber树之后切换成current Fiber,内存中间接一次性切换,进步了性能
- Fiber的存在使异步可中断的更新成为了可能,作为工作单元,能够在工夫片内执行工作,没工夫了交还执行权给浏览器,下次工夫片继续执行之前暂停之后返回的Fiber
- Fiber能够在reconcile的时候进行相应的diff更新,让最初的更新利用在实在节点上
hooks
为什么hooks不能写在条件判断中
答:hook会按顺序存储在链表中,如果写在条件判断中,就没法放弃链表的程序
状态/生命周期
setState是同步的还是异步的
答:legacy模式下:命中batchedUpdates时是异步 未命中batchedUpdates时是同步的
concurrent模式下:都是异步的
componentWillMount、componentWillMount、componentWillUpdate为什么标记UNSAFE
答:新的Fiber架构能在scheduler的调度下实现暂停持续,排列优先级,Lane模型能使Fiber节点具备优先级,在高优先级的工作打断低优先级的工作时,低优先级的更新可能会被跳过,所有以上生命周期可能会被执行屡次,和之前版本的行为不统一。
组件
react元素$$typeof属性什么
答:用来示意元素的类型,是一个symbol类型
react怎么辨别Class组件和Function组件
答:Class组件prototype上有isReactComponent属性
函数组件和类组件的相同点和不同点
答:相同点:都能够接管props返回react元素
不同点:
编程思维:类组件须要创立实例,面向对象,函数组件不须要创立实例,接管输出,返回输入,函数式编程
内存占用:类组建须要创立并保留实例,占用肯定的内存
值捕捉个性:函数组件具备值捕捉的个性 上面的函数组件换成类组件打印的num一样吗
export default function App() { const [num, setNum] = useState(0); const click = () => { setTimeout(() => { console.log(num); }, 3000); setNum(num + 1); }; return <div onClick={click}>click {num}</div>;}export default class App extends React.Component { state = { num: 0 }; click = () => { setTimeout(() => { console.log(this.state.num); }, 3000); this.setState({ num: this.state.num + 1 }); }; render() { return <div onClick={this.click}>click {this.state.num}</div>; }}
可测试性:函数组件不便测试
状态:类组件有本人的状态,函数组件没有只能通过useState
生命周期:类组件有残缺生命周期,函数组件没有能够应用useEffect实现相似的生命周期
逻辑复用:类组件继承 Hoc(逻辑凌乱 嵌套),组合优于继承,函数组件hook逻辑复用
跳过更新:shouldComponentUpdate PureComponent,React.memo
倒退将来:函数组件将成为支流,屏蔽this、标准、复用,适宜工夫分片和渲染
开放性问题
- 说说你对react的了解/请说一下react的渲染过程
答:是什么:react是构建用户界面的js库能干什么:能够用组件化的形式构建疾速响应的web应用程序如何干:申明式(jsx) 组件化(不便拆分和复用 高内聚 低耦合) 一次学习随处编写做的怎么样: 优缺(社区凋敝 一次学习随处编写 api简介)毛病(没有零碎解决方案 选型老本高 过于灵便)设计理念:跨平台(虚构dom) 疾速响应(异步可中断 增量更新)性能瓶颈:cpu io fiber工夫片 concurrent mode渲染过程:scheduler render commit Fiber架构 - 聊聊react生命周期
详见第11章 - 简述diff算法
详见第9章 - react有哪些优化伎俩
答:shouldComponentUpdate、不可变数据结构、列表key、pureComponent、react.memo、useEffect依赖项、useCallback、useMemo、bailoutOnAlreadyFinishedWork ... - react为什么引入jsx
答:jsx申明式 虚构dom跨平台解释概念:jsx是js语法的扩大 能够很好的形容ui jsx是React.createElement的语法糖想实现什么目标:申明式 代码构造简洁 可读性强 构造款式和事件能够实现高内聚 低耦合 、复用和组合 不须要引入新的概念和语法 只写js, 虚构dom跨平有哪些可选计划:模版语法 vue ag引入了控制器 作用域 服务等概念jsx原理:babel形象语法树 classic是老的转换 automatic新的转换 - 说说virtual Dom的了解
答:是什么:React.createElement函数返回的就是虚构dom,用js对象形容实在dom的js对象长处:解决了浏览器的兼容性 防备xss攻打 跨平台 差异化更新 缩小更新的dom操作毛病:额定的内存 首次渲染不肯定快 - 你对合成事件的了解
类型 | 原生事件 | 合成事件 |
---|---|---|
命名形式 | 全小写 | 小驼峰 |
事件处理函数 | 字符串 | 函数对象 |
阻止默认行为 | 返回false | event.preventDefault() |
了解:
- React把事件委托到document上(v17是container节点上)
- 先解决原生事件 冒泡到document上在解决react事件
- React事件绑定产生在reconcile阶段 会在原生事件绑定前执行
相干参考视频解说:进入学习
劣势:
- 进行了浏览器兼容。顶层事件代理,能保障冒泡一致性(混合应用会呈现凌乱)
- 默认批量更新
- 防止事件对象频繁创立和回收,react引入事件池,在事件池中获取和开释对象(react17中废除)
react17事件绑定在容器上了 - 咱们写的事件是绑定在
dom
上么,如果不是绑定在哪里?
答:v16绑定在document上,v17绑定在container上 - 为什么咱们的事件手动绑定
this
(不是箭头函数的状况)
答:合成事件监听函数在执行的时候会失落上下文 - 为什么不能用
return false
来阻止事件的默认行为?
答:说到底还是合成事件和原生事件触发机会不一样 react
怎么通过dom
元素,找到与之对应的fiber
对象的?
答:通过internalInstanceKey对应
解释后果和景象
- 点击Father组件的div,Child会打印Child吗
function Child() { console.log('Child'); return <div>Child</div>;}function Father(props) { const [num, setNum] = React.useState(0); return ( <div onClick={() => {setNum(num + 1)}}> {num} {props.children} </div> );}function App() { return ( <Father> <Child/> </Father> );}const rootEl = document.querySelector("#root");ReactDOM.render(<App/>, rootEl);
答: 不会,源码中是否命中bailoutOnAlreadyFinishedWork
- 打印程序是什么
function Child() {useEffect(() => {console.log('Child');}, [])return <h1>child</h1>;}function Father() {useEffect(() => {console.log('Father');}, [])return <Child/>;}function App() {useEffect(() => {console.log('App');}, [])return <Father/>;}
答:Child ,Father ,App ,render阶段mount时深度优先遍历,commit阶段useEffect执行机会
- useLayout/componentDidMount和useEffect的区别是什么
class App extends React.Component { componentDidMount() { console.log('mount'); }}useEffect(() => { console.log('useEffect');}, [])
答:他们在commit阶段不同机会执行,useEffect在commit阶段结尾异步调用,useLayout/componentDidMount同步调用
- 如何解释demo_4、demo_8、demo_9呈现的景象
答:demo_4:useEffect和useLayoutEffect的区别
demo_8:工作的优先级无关,见源码剖析视频
demo_9:批量更新无关,见源码剖析视频