React Hook学习笔记

  1. 用到的库
    qs: get请求时转义请求的参数 yarn add qs emtion: css in js库之一 craco: 自主定义package.json中的脚本, npm run eject的替代方案 craco-less dayjs 处理日期格式 ## momentjs 已经停止维护 react-query: react-error-boundary: react 错误边界库 react-helmet: 修改react项目 header中的内容 meta title等

    【React Hook学习笔记】encodeURIComponent 转义get请求的参数
    encodeURI 转义整个请求的链接
  2. 封装常用的自定义的hook
    useMount: export const useMount = (callback: (...rest: any) => any) => { // 依赖项中,加入callback会造成无限循环,这和useCallback &&useMemo有关 useEffect(() => callback(), []); }; useHttp useAsync useDocument

  3. fetch 不会抛异常
    fetch().then().catch() catch 抛异常的条件:断网,网络不通,请求错误5xx, 4xx 不会抛异常,所以 需要在then中用户根据返回的结果手动抛Promise.reject(...)

  4. 样式方案
    1. 使用antd 组件库 2. css in js库 --> emotion 3. grid布局 4.

  5. css in js --> 一种组织代码的方式 && css方案
    emotion的使用与安装
    yarn add @emotion/react @emotion/styled; 编辑器安装插件的支持【styled components && styled jsx】 组件中引入 import styled from '@emotion/styled' 代码组织: const Container = styled.div` display: flex; ` !!!styled.xxxx只能是原生的html标签,那如果引用的是Antd库的组件咋办?==> const ShadowCard = styled(Card)` // 仅以Card举例 width: 40rem; ` ### Card 替换成对应的需要修饰的 Antd 或者其他UI库组件名

    全局样式的
    html { /* rem em */ /*em 相对于父元素的font-size*/ /*rem 相对于根元素html的font-size, r就是root的意思*/ /*16 * 62.5% = 10px*/浏览器默认的font-size: 16 /*1rem === 10px*/ font-size: 62.5%; // ==> 此时 1rem === 10px }/*viewport height === vh*/ html body #root .App { min-height: 100vh; // 视口的高度 }

  6. 网格布局
    const Container = styled.div` display: grid; grid-template-rows: 6rem 1fr 6rem; grid-template-columns: 20rem 1fr 20rem; grid-template-areas: "header header header" "nav main aside" "footer footer footer"; height: 100vh; grid-gap: 10rem; `; #1. 1fr 自由伸缩 // grid-area 用来给grid子元素起名字 const Header = styled.header` grid-area: header; ...... `; const HeaderRight = styled.div``; const Main = styled.main` grid-area: main; `; const Nav = styled.nav` grid-area: nav; `; const Aside = styled.aside` grid-area: aside; `; const Footer = styled.footer` grid-area: footer; `;

    grid flex 使用场景
    *从内容出发:你先有一组内容(数量一般不固定),然后希望他们均匀的分布在容器中,由内容自己的大小决定占据的空间
    *从布局出发:先规划网格(数量一般比较固定),然后再把元素往里填充
    1. 一维布局 || 从内容出发:flex
    2. 二维布局 || 从布局出发:grid
  7. svg的图片以svg的方式渲染
    import { ReactComponent as SoftwareLogo } from "assets/software-logo.svg";

  8. 自定义Error && Loading组件 --> 自定义useAsync统一处理loading&&error
  9. 错误边界
    import React, { Children, ReactNode } from 'react'type ErrorType = { error: Error | null }// React.ReactElement JSX的类型 type FallbackRender = (props: ErrorType) => React.ReactElementtype PropsType = { children: ReactNode, fallbackRender: FallbackRender } // or 利用联合类型 type PropsType2 = React.PropsWithChildren<{fallbackRender: FallbackRender}>export class ErrorBoundary extends React.Component { state = {error: null}// 当子组件抛出异常,这里会接收到并调用 static getDerivedStateFromError(error: Error) { return {error} // 自动设置state }render() { const {error} = this.state const { fallbackRender, children} = this.propsif (error) return fallbackRender({error})return children } }

  10. useRef Hook闭包案例
    export const useDocumentTitle = (title: string, keepOnUnmount: boolean = true) => { const oldTitle = document.title // 页面加载时:oldTitle === 旧title 'React App' // 加载后:oldTitle === 新titleuseEffect(() => { document.title = title }, [title])useEffect(() => { return () => { if (!keepOnUnmount) { // 如果不指定依赖,读到的就是就title document.title = oldTitle } } }, []) }const test = () => { let num = 0; const effect = () => { num += 1 const message = `现在的num值: ${num}` return function unmmount() { console.log(message) } }return effect }const add = test() const unmount = add() add() add() unmount() /// 打印几?export const useDocumentTitle2 = (title: string, keepOnUnmount: boolean = true) => { /** * 官网:useRef返回一个可变的ref对象,其.current属性被初始化为传入的参数(initialValue)。 * 返回的ref对象在组件的生命周期内保持不变 */ const oldTitle = useRef(document.title).current; useEffect(() => { document.title = title }, [title])useEffect(() => { return () => { if (!keepOnUnmount) { // 如果不指定依赖,读到的就是就title document.title = oldTitle } } }, [title, keepOnUnmount]) }

    test.tsx
    import { useEffect, useState } from "react"export const Test = () => { const [num, setNum] = useState(0)const add = () => setNum(num + 1)/** * useEffect中引用的num是 只有页面加载时执行一次,里面形成一个闭包,而其作用域引用的num是页面刚加载时候的值 * 怎么保证里面拿到的值 是新鲜的呢?在effect中 [xxx] 依赖项 */ useEffect(()=>{ setInterval(() => { console.log('num in setInterval:', num) }) }, [])useEffect(() => { return () => { console.log(num) } }, [])return {num}
    }

    推荐阅读