Home
ExampleToolsChat

react基础

Category:

Tags:

react基础

如何使用react

  1. Quick start和api Reference和installation的概念

写React工程时, 并不会用到所有的api 只会用到特别常用的api

  1. 使用方式
    1. script标签引入
    2. 脚手架使用
  2. react核心包
    1. React
      1. React.createElement("div",{},"hello react") -> ReactEl
    2. ReactDOM
      1. ReactDOM.createRoot(el ) // 创建工作节点
      2. root.render(ReactEl) // 渲染页面

核心功能放在React内, 不包含任何宿主环境代码(document.getElementById)

React将对宿主操作能力放到ReactDOM中


唤醒相机,录音放在ReactNative中处理
  1. jsx使用 一种表达html结构的语法
    1. React.createElement("div",{},"hello react") -> 传入的对象
      1. {onClick:()=>{}} => 也就是说,给ReactEl加上属性 [class -> className]
    2. 由于多个dom被React.createElement会导致不好书写而且麻烦,则有jsx
    3. 使用jsx前提, 导入babel解析(语法降级)jsx文件
      1. script挂上type="text/babel",表达是将代码交给babel解析, 默认值为text/javascript
      2. 浏览器只会解析script的type为text/javascript和module,而babel解析type为text/babel中的代码,通过转换后加入新的script标签并写入其中
      3. 用书写jsx的方式创建ReactEl
        1. // 创建工作节点 const root = ReactDOM.createRoot(document.getElementById("root")); // 传入ReactEl const reactEl = ( <div> 123<h1>456</h1> </div> ); root.render(reactEl);

React-cli脚手架的使用

  1. 什么是脚手架,提供一系列预设,让开发者无需考虑除了自身意外的其他外部问题
  2. npx -> npm的附带产物
    1. 去执行一段命令, npx会先看第一个参数是否有安装,没有则用npm临时安装,再执行后续命令

      text
      npx create-react-app my-app

React组件

  1. 组件允许我们将UI划分为独立的,可重用的部分
  2. 要求
    1. 组件名必须大写(小写为ReactEl,大写为组件)
    2. 组件必须返回ReactEl
      1. null/ReactEl/组件/可迭代对象
  3. 组件状态
    1. 组件内部数据发生变化,如何使页面发生变化
      1. 渲染 === 函数组件执行
      2. 改变了页面依赖的值,要重新渲染函数组件 -> [count, setCount] = useState(0)
        1. 组件状态发生变化
        2. 组件属性发生变化
    2. 组件状态更新是异步的,状态的更新是批量进行的
  4. 组件属性
    1. 给组件传递属性就相当于给函数传递参数

React事件机制

  1. jsx语法 -> babel -> React.createEl -> 真实dom
  2. jsx转化的真实dom身上的事件监听不会绑定在任何dom上,React会保存jsx的身上对应注册的事件,并在root上处理
  3. React事件池机制 -> e.target无法被捕捉(共用event提高性能)

受控标签和非受控标签

  1. 受控标签:状态完全由他人控制,自身没有任何决定的权力
    1. 受控属性 -> value
  2. 非标签组件:自由的
    1. 只能通过defaultValue设置初始值,监听事件获取内部值

hooks使用之useState

hooks:允许开发者在不写类组件下的情况下去生成state以及一些其他曾经是类组件专属的东西

useState是一个react的hook, 让我们可以在组件内定义状态
  1. useState(initState) -> initState如果是函数的话, 必须是纯函数, 参数不会解析
  2. react严格模式
  3. immutable state 不可变状态, 每一次状态传递都是不可变的

hooks使用之useEffect

用来处理副作用

http请求/dom操作
  1. useEffect(setup, dependencies?)

    1. setup初始化
    2. dependencies? 依赖数组
  2. 执行时机:

    1. 当我们使用useEffect去注册setup,React会在该组件每次挂载完毕到页面时会执行setup函数,异步执行
    2. 当依赖项发生变更时, 会执行对应setup
  3. 应用场景

    1. http请求
  4. 清除副作用

    1. 组件被卸载时内部的监听该销毁
    2. setup函数有一个返回值,为清理函数,会在组件销毁时执行(销毁监听事件,定时器)
    text
     useEffect(() => {    const defaultValue = 10;    setCount(defaultValue);    const handleKeyDown = (e) => {      console.log(e.code);   };    window.addEventListener("keydown", handleKeyDown);    return () => {      window.removeEventListener("keydown", handleKeyDown);   }; }, [count]);

hooks自定义实现之useRequestLoading()

text
export default function useRequestLoading(PromiseFn) {  const [loading, setLoading] = useState(false);  const execRequset = async () => {    setLoading(true);    await PromiseFn();    setLoading(false); };  return {    loading,    execRequset, }; }
text
// 原写法  const [useList, setUserList] = useState([]);  const [loading, setLoading] = useState(false); ​  const fetchUserList = async () => {    setLoading(true);    const useListResp = await getUserList();    setUserList(useListResp);    setLoading(false);    requestIdleCallback(() => {}); };  useEffect(() => {    fetchUserList(); }, []);  return (    <div>      <h1>用户列表</h1>     {loading ? (        <div>loading...</div>     ) : (        useList.map((user) => <div key={user.id}>{user.name}</div>)     )}    </div> ); // hook写法  const [useList, setUserList] = useState([]);  const { loading, execRequset } = useRequestLoading();  useEffect(() => {    execRequset(async () => {      const result = await getUserList();      setUserList(result);   }); }, []);  return (    <div>      <h1>用户列表</h1>     {loading ? (        <div>loading...</div>     ) : (        useList.map((user) => <div key={user.id}>{user.name}</div>)     )}    </div> );

hooks自定义实现之useForceUpdate

text
export default function useForceUpdate() {  const [_, setCompState] = useState({});  function forceUpdate() {    setCompState({}); }  return forceUpdate; } ​

hooks自定义实现之useScrollWatcher

text
export default function useMouseWatcher(moveCallback) {  useEffect(() => {    const removeEvent = () => {      window.removeEventListener("mousemove", moveCallback);   };    window.addEventListener("mousemove", moveCallback);    return removeEvent; }, []); } // 实现  const [pos, setPos] = useState({ x: 0, y: 0 });  const removeEvent = useMouseWatcher((e) => {    console.log("listender", e.pagx, e.pageY);    setPos({ x: e.pageX, y: e.pageY }); });  return (    <div>      <h2>滚动监听</h2>      <button onClick={removeEvent}>移除监听</button>      <div>       pos:{pos.x}-{pos.y}      </div>    </div> );

内置hooks使用

用来长期稳定的维护某一个函数引用,

  1. useCallback(initFn,depenece)

    1. 只有当依赖发生变化时,initFn的应引用才会改变

      text
      const addCount2 = useCallback(() => {   console.log("执行了addCount2函数", count2);   setCount2((pre) => pre + 1); }, [count]); // 当count发生变化时,addCount2的引用才刷新
    2. dependness 依赖项发生变化以后,函数内引用会刷新

  2. useMemo(initFn) -> 类似vue的计算属性

    1. 第一个参数是一个函数,会被React直接执行并缓存,
    2. 第二个为依赖 当以来发生变化时吗, 重新缓存
  3. useRef -> 类似vue的 dom ref

    <></> 语法糖 -> React.Fragment

    1. 构建一个状态,这个状态脱离react控制,他的变化不会造成组件重新渲染,同时状态不会再次初始化

      text
       const [timer, setTimer] = useState(60);  let timerId = useRef(null);  console.log("刷新了页面");  const start = useCallback(() => {    console.log("点击了start");    timerId.current = setInterval(() => {      setTimer((pre) => pre - 1);   }, 1000); }, []);  const stop = useCallback(() => {    if (timerId.current) clearInterval(timerId.current); }, [timerId]);
    2. 挂真实dom,自动在useEffect内获取当前dom

      text
      import React, { useRef } from "react"; ​ export default function TestInput() {  const inputElRef = useRef();  const focus = () => {    inputElRef.current.focus(); };  return (    <>      <input ref={inputElRef} type="text" />      <button onClick={focus}>focus input!</button>      <hr />    </> ); } ​
    3. 可读可写的,

  4. ForwordRef() -< 给函数组件扩展一个ref属性作为第二参数

  5. useImperativeHandle 当以来发生变化时, 才会给ref.current刷新值

    1. 第一个参数ref
    2. 第二个参数fn -< 返回值为ref.current
    3. 第三个参数为依赖项
  6. useContent

    解决props以外的数据共享,将多层组件数据共享简化, 用来做全局数据共享的

    1. 通过ThemeContent.Provider传递给内容上下文
      1. 通过ThemeContent.Provide传递value
      2. 后代组件通过useContent(ThemeContent), 获取value
  7. useLayoutEffect()

    1. useEffect方法当首次渲染工作完成并将真实dom生成页面以后, 并肩对应回调函数推入异步队列等待执行
    2. useLayoutEffect方法当首次渲染工作完成并将真实dom生成页面以后, 并肩对应回调函数推入同步队列等待执行

浏览器渲染帧探究

  1. 浏览器一帧需要做的事
    1. 处理上一帧的用户交互事件
    2. 调用requestAnimationFrame
    3. 执行重排重绘
    4. 调用requestIdleCallback
  2. 掉帧
  3. react调度机制

React渲染原理之concurrency(并发性, 可中断渲染)

  1. React渲染一个组件到页面中要做哪些事情
    1. 拿到React.createElement所返回的ReactEl节点 -> 是个对象
    2. 通过render进行渲染
      1. 如果是react元素节点的话就生成dom插入 appendChild
      2. 如果是组件这会在渲染保存对应的hooks以及触发对应的hooks
    3. 更新 -> diff
  2. react将渲染流程分为了两个阶段
    1. render:负责将需要渲染的组件的内部逻辑以及react内部逻辑并执行得到一份fiber清单[记录了要展示的真是dom树是什么样子,要增加哪些dom]
    2. commit:负责将fiber清单转换成真实dom