关于react.js:react源码解析20总结第一章的面试题解答

35次阅读

共计 4749 个字符,预计需要花费 12 分钟才能阅读完成。

总结

至此咱们介绍了 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 章介绍了新版事件零碎,包含事件生产、监听和触发,

面试题简答(详见视频源码角度解说)

  1. jsx 和 Fiber 有什么关系

    答:mount 时通过 jsx 对象(调用 createElement 的后果)调用 createFiberFromElement 生成 Fiber
    update 时通过 reconcileChildFibers 或 reconcileChildrenArray 比照新 jsx 和老的 Fiber(current Fiber)生成新的 wip Fiber 树

  2. 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'});
}
  1. Fiber 是什么,它为什么能进步性能

    答:Fiber 是一个 js 对象,能承载节点信息、优先级、updateQueue,同时它还是一个工作单元。

    1. Fiber 双缓存能够在构建好 wip Fiber 树之后切换成 current Fiber,内存中间接一次性切换,进步了性能
    2. Fiber 的存在使异步可中断的更新成为了可能,作为工作单元,能够在工夫片内执行工作,没工夫了交还执行权给浏览器,下次工夫片继续执行之前暂停之后返回的 Fiber
    3. Fiber 能够在 reconcile 的时候进行相应的 diff 更新,让最初的更新利用在实在节点上

hooks

  1. 为什么 hooks 不能写在条件判断中

    答:hook 会按顺序存储在链表中,如果写在条件判断中,就没法放弃链表的程序

状态 / 生命周期

  1. setState 是同步的还是异步的

    答:legacy 模式下:命中 batchedUpdates 时是异步 未命中 batchedUpdates 时是同步的

    concurrent 模式下:都是异步的

  2. componentWillMount、componentWillMount、componentWillUpdate 为什么标记 UNSAFE

    答:新的 Fiber 架构能在 scheduler 的调度下实现暂停持续,排列优先级,Lane 模型能使 Fiber 节点具备优先级,在高优先级的工作打断低优先级的工作时,低优先级的更新可能会被跳过,所有以上生命周期可能会被执行屡次,和之前版本的行为不统一。

组件

  1. react 元素 $$typeof 属性什么

    答:用来示意元素的类型,是一个 symbol 类型

  2. react 怎么辨别 Class 组件和 Function 组件

    答:Class 组件 prototype 上有 isReactComponent 属性

  3. 函数组件和类组件的相同点和不同点

    答:相同点:都能够接管 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、标准、复用,适宜工夫分片和渲染

开放性问题

  1. 说说你对 react 的了解 / 请说一下 react 的渲染过程
    答:是什么:react 是构建用户界面的 js 库能干什么:能够用组件化的形式构建疾速响应的 web 应用程序如何干:申明式(jsx)组件化(不便拆分和复用 高内聚 低耦合)一次学习随处编写做的怎么样:优缺(社区凋敝 一次学习随处编写 api 简介)毛病(没有零碎解决方案 选型老本高 过于灵便)设计理念:跨平台(虚构 dom)疾速响应(异步可中断 增量更新)性能瓶颈:cpu io fiber 工夫片 concurrent mode 渲染过程:scheduler render commit Fiber 架构
  2. 聊聊 react 生命周期
    详见第 11 章
  3. 简述 diff 算法
    详见第 9 章
  4. react 有哪些优化伎俩
    答:shouldComponentUpdate、不可变数据结构、列表 key、pureComponent、react.memo、useEffect 依赖项、useCallback、useMemo、bailoutOnAlreadyFinishedWork …
  5. react 为什么引入 jsx
    答:jsx 申明式 虚构 dom 跨平台解释概念:jsx 是 js 语法的扩大 能够很好的形容 ui jsx 是 React.createElement 的语法糖想实现什么目标:申明式 代码构造简洁 可读性强 构造款式和事件能够实现高内聚 低耦合、复用和组合 不须要引入新的概念和语法 只写 js,虚构 dom 跨平有哪些可选计划:模版语法 vue ag 引入了控制器 作用域 服务等概念 jsx 原理:babel 形象语法树 classic 是老的转换 automatic 新的转换
  6. 说说 virtual Dom 的了解
    答:是什么:React.createElement 函数返回的就是虚构 dom,用 js 对象形容实在 dom 的 js 对象长处:解决了浏览器的兼容性 防备 xss 攻打 跨平台 差异化更新 缩小更新的 dom 操作毛病:额定的内存 首次渲染不肯定快
  7. 你对合成事件的了解
类型 原生事件 合成事件
命名形式 全小写 小驼峰
事件处理函数 字符串 函数对象
阻止默认行为 返回 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 对应

解释后果和景象

  1. 点击 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

  1. 打印程序是什么
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 执行机会

  1. useLayout/componentDidMount 和 useEffect 的区别是什么
class App extends React.Component {componentDidMount() {console.log('mount');
  }
}

useEffect(() => {console.log('useEffect');
}, [])

答:他们在 commit 阶段不同机会执行,useEffect 在 commit 阶段结尾异步调用,useLayout/componentDidMount 同步调用

  1. 如何解释 demo_4、demo_8、demo_9 呈现的景象
    答:demo_4:useEffect 和 useLayoutEffect 的区别
    demo_8:工作的优先级无关,见源码剖析视频
    demo_9:批量更新无关,见源码剖析视频

正文完
 0