Skip to content

react

参考资源

core-content

生命周期及渲染

要点

  • 首次渲染,更新,卸载
  • 父组件更新,子组件默认更新
  • React.memo, useMeo, useCallback的使用时机

class组件

  • class组件才有生命周期:constructor, render, componentDidMount, componentDidUpdate, componentWillUnmount, shouldComponentUpdate, getDerivedStateFromProps, getSnapshotBeforeUpdate, componentDidCatch, static getDerivedStateFromError
  • https://juejin.cn/post/7096137407409422344#heading-0

函数式组件

渲染机制

  • 组件渲染的核心机制: 父组件更新,子组件默认更新;
  • React.memo: 用于函数式组件,用于优化子组件的渲染,在父组件更新时,子组件默认会更新,但是如果用react.memo包裹起来,就不会重新更新了;当组件的props没有变化时,就不会重新渲染,比如,组件的一个props时callback,这个时候引用变了,也会重新更新,父组件里可以用useCallback包裹起来,这样就不会重新更新了;对于比较繁杂的计算或者结果,可以用useMemo包裹起来,避免重复计算;useMemo和useCallback的区别是,useMemo是返回一个值,useCallback是返回一个函数;useEffect可能会有闭包陷阱的问题,可以用useRef来解决这个问题,useRef通过指针拿到的都是最新的值,useRef还可以拿到dom的引用;
  • useEffect 是异步执行的,而useLayoutEffect是同步执行的。useEffect 的执行时机是浏览器完成渲染之后,而 useLayoutEffect 的执行时机是浏览器把内容真正渲染到界面之前,和 componentDidMount 等价。

react懒加载

react的事件机制


react hook

副作用

  • react组件的本质就是:ui=f(data), 跟着渲染和交互无关的都是副作用,组件是个纯函数;
  • https://www.zhihu.com/question/303338688/answer/1753583388
  • 那么常见的副作用有哪些: 在函数体内修改函数外变量的值,调用会产生副作用的函数, http请求, Date.now()、Math.random()等不确定性方法等等,总结:具有不确定性的操作,你都可以理解为是不纯的,不纯的那么意味可能带来副作用。

react hook 原理


组件的更新机制

  • 组件的更新逻辑: 参考上述渲染逻辑;
  • 节点更新机制,fiber 机制, diff算法,最小编辑距离;
  • 原理:
    参考1: https://juejin.cn/post/6844904061838295047 其中react部分; 参考2: 参考mini demo react的实现;

mini demo react


react组件的状态管理

redux

  • redux的技巧: 大型react、redux项目, trace回溯技巧:window.REDUX_DEVTOOLS_EXTENSION_COMPOSE,设置trace =true, webpack打包要设置--devtool source-map, 这样就可以看到dispatch的调用栈了;

react的事件机制


react router


react ssr


简化题目

实现简化版的render和h函数

js
function h(tagName, attributes, children /* Your Code HERE */) {
  /* Your Code HERE */
  // 把vdom => element
  let element = document.createElement(tagName);
  for (const key of Object.keys(attributes)) {
    // console.log(key)
    if (key === "on") {
      // element.setAttribute('click', attributes[key].click)
      element.addEventListener("click", (event) => {
        attributes[key].click();
      });
    }
    element.setAttribute(key, attributes[key]);
  }
  if (Array.isArray(children)) {
    // console.log('test1', children)
    // element.appendChild(children)
    for (const item of children) {
      let childItem = item;
      if (typeof item === "string") {
        childItem = document.createTextNode(item);
      }
      element.appendChild(childItem);
    }
  } else if (typeof children === "string") {
    // element.innerHtml = children
    let childItem = document.createTextNode(children);
    element.appendChild(childItem);
  }

  return element;
}

function patch(containerElement, element) {
  /* Your Code HERE */
  // element => container
  if (containerElement) {
    containerElement.innerHtml = "";
    containerElement.appendChild(element);
  }
}

const container = document.getElementById("container");

function handleClick() {
  console.log("clicked");
}

const vnode = h(
  "div",
  { id: "element", class: "two classes", on: { click: handleClick } },
  [
    h("span", { class: "text-class1" }, "This is black"),
    " and this is just normal text",
    h("a", { href: "/foo" }, "I'll take you places!"),
  ]
);

// Patch into empty DOM element
patch(container, vnode);