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等
    

    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.xx  xx只能是原生的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.ReactElement
    
    type 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.props
    
            if (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 === 新title
    
        useEffect(() => {
            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}

    }

你可能感兴趣的:(react.js)