• readme


    react

    • 是一个用于构建用户界面的 javascript 库

    1 hello world

    • 需要安装两个包: npm install react react-dom
    • 要支持 jsx 语法,需要 react
    • 要支持 dom 渲染,需要 react-dom
    // 引入react支持jsx语法
    import React from "react"; // 此处导入的变量名必须是React
    import { createRoot } from "react-dom/client";
    
    // 先体验jsx语法书写我们的html结构
    const ele = <h1>hello world</h1>;
    
    // 把上面的html结构渲染到#app里面
    const root = createRoot(document.getElementById("app"));
    root.render(ele);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2 JSX

    • jsx 语法不是字符串也不是 html
    • 更偏向 js,具有 js 的完整功能
    • 最外层如果是一个元素可以直接写
    • 最外层如果是多一个元素要写在数组里面,最外层的数组外面不用写{}
    • 标签的属性名需要小驼峰命名,属性 class 要写成 className
    • 如果属性值是字符串用引号包括,如果是 js 表达式用{}, 引号和{}不能同时使用
    • Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用,最后会生成一个 react 元素
    • 具体代码见:src/12k/01learnJsx.jsx

    3 类组件和函数组件

    • 书写组件最简单的方法是函数组件
    • 类组件里面有 this 是组件实例对象
    • 函数组件里面没有 this,this 是 undefined
    • 自定义组件名要求首字母驼峰命名
    • 类组件语法 - 利用 es6 的 class 语法
    • 具体代码见:src/12k/02learnComponent.jsx
    class MyHome extends React.Component {
      // 里面必须实现render方法
      render() {
        // return的内容就是组件的html结构
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 函数组件的语法
    function MyFooter() {
      // return的内容就是组件的html结构
    }
    
    • 1
    • 2
    • 3

    4 props

    • 自定义组件可以当标签使用,标签上都有属性
    • 书写标签上的任意属性,在自定义组件内部可以通过 props 接收
    • 书写标签内的元素,在自定义组件内容可以通过 props 接收
    • 类组件通过: this.props 接收,其中标签内的元素通过 this.props.children 接收
    • 函数组件通过: 函数的第一个形参接收 props,标签内的元素通过 props.children 接收
    • 自定义组件和原生的 dom 元素的区别
      • 原生的 dom 元素是小写的,自定义组件是首字母大写的
      • 原生的标签上的属性值最后一定是字符串,自定义组件上的属性值可以是任意类型
      • 自定义组件上的属性如果只写属性不写值,表示值是 true
    • 在自定义组件内部不要修改 props,是只读的
    • 具体代码见:src/12k/03learnProps.jsx

    5 元素渲染

    • 一个 react 元素一旦创建,就不可变
    • 如果要更新一个 react 元素
    • 目前只能重新创建一个新的 react 元素
    • 然后渲染到根节点中
    • 渲染 dom 元素的时候,会把本次 react 元素对象和上一次的 react 元素对象对比
    • 只更新必要的部分
    • 具体代码见:src/main.jsx的第四个部分

    6 props 类型检查

    • 官方推荐: prop-types
    • 在 v15.5 之前包含在 react 里面,后面独立成一个库:prop-types
    • 安装:npm install prop-types -S
    • 使用
    import PropTypes from "prop-types";
    import React from "react";
    class MyHome extends React.Component {
      render() {}
    }
    // 设置MyHome接收的属性props的类型和是否必须
    MyHome.propTypes = {
      name: PropTypes.string.isRequired, // name是字符串类型,而且是必须传入的,有默认值算传入了
      age: PropTypes.number,
      love: PropTypes.array,
      fn: PropTypes.func,
      bool: PropTypes.bool,
      obj: PropTypes.object,
      node: PropTypes.node, // react可以直接渲染的类型
      element: PropTypes.element, // react元素
      message: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
      gender: PropTypes.oneOf(["男", "女"]),
    };
    MyHome.defaultProps = {
      name: "lucy",
    };
    
    const ele = <MyHome name="lily" {...}/>;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    7 在 jsx 语法中书写注释

    • jsx 是偏 js,所以注释是 js 代码,也要写在{}里面
    • 最后注释就下面这个样子,不能使用 双斜杠
    conse ele = <div>
      {/* 我是注释 */}
      hello world
    <div>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    8 回忆原生 js 中的 this 指向问题

    • 如果是事件处理函数调用,里面的 this 是事件源,里面的 event 是事件对象
    • 如果是普通函数调用,里面的 this 非严格模式是 window,严格模式是 undefined
    • 如果是对象的方法调用,里面的 this 是当前调用方法的对象
    • 如何改变 this 的指向
      • fn(实参 1,实参 2,…) - 没有改变 this 的指向
      • fn.call(改变成的 this 指向,实参 1,实参 2,…) - 只改变本此调用的 this
      • fn.apply(改变成的 this 指向,[实参 1,实参 2,…]) - 只改变本此调用的 this
      • let newFn = fn.bind(改变成的 this 指向) - 不调用函数,生成一个新的函数 newFn,newFn 不管怎么调用 this 都固定

    9 state - 类似 vue 里面的 data

    • state 只能在构造函数中初始化赋值
    • state 不能直接修改,要通过 setState 修改
    • setState 的更新可能是异步的
    • setState 的更新会进行浅合并,只合并同一个函数域
    • 如果 setState 修改的值依赖上一次的值,setState 传入的参数就必须是一个函数
    • 语法 1: 不依赖上一次的值
    this.setState(
      {
        num: 100,
      },
      () => {
        // 第二个参数的回调函数会在更新完成以后调用
        console.log(this.state);
      }
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 语法 2: 依赖上一次的值
    this.setState((state) => {
      return {
        num: state.num + 1,
      };
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5

    10 组件生命周期 - lifeCycle

    • 组件生命周期分为 3 大部分
      • 挂载时:constructor,render,componentDidMount
      • 更新时:shouldComponentUpdate,render,componentDidUpdate
      • 卸载时:componentWillUnmount
    • constructor
      • 构造函数,第一行:super()
      • 初始化组件状态(初始化声明式变量):this.state = {count:1,num:100}
        • 构造函数中可以直接 state 赋值,不要写 setState
      • 不要在构造函数中开定时器,不要调用接口
    • 挂载时: render
      • 挂载时必定执行一次 render,不能通过 shouldComponentUpdate 阻止
      • render 是类组件必须的一个生命周期
      • 返回值是视图结构(JSX,Fiber 树,React 元素)
      • 可以做数据处理,一般是解构一些数据
      • 不调用接口,不开启定时器,不要写 setState
    • componentDidMount
      • react 元素变成了 dom
      • 此时数据变成了真实的 dom
      • 可以初始化一些需要 dom 的操作,可以开启定时器,可以请求接口
    • 更新时:render
      • 如果有 new Props,setState,forceUpdate,会触发 render 函数
      • 但是:
      • forceUpdate 一定触发 render 函数
      • new Props,setState 在触发 render 函数之前会进过 shouldComponentUpdate
      • 如果不写 shouldComponentUpdate,就必然进入 render
    • shouldComponentUpdate - react 的性能优化点
      • 有两个参数:
      • 第一个参数是:nextProps
      • 第二个参数是:nextState
      • 返回值是布尔值,如果是 true,就进入 render,如果是 false,就不进入 render
      • 我们理想中的 shouldComponentUpdate 应该是,props 或者 state 有变化才进入 render,如果没有变化就不进入 render
      • 我们自己写难度大,所有可以继承 React.PureComponent,他帮我们实现了基本的 shouldComponentUpdate 的上述功能
    • componentDidUpdate
      • 有两个参数:
      • 第一个参数是:prevProps
      • 第二个参数是:prevState
      • 新的 dom 节点,更新完成,依赖新的 dom 的操作可以写在这里
      • 不要写定时器,不要调用接口,不要写 setState
    • componentWillUnmount
      • 组件卸载的时候调用的函数
      • 可以在里面进行清理操作,一般是:清除定时器,取消请求等

    11 事件处理

    • react 的事件处理和 dom 的事件处理基本一致
    • react 的事件名称用小驼峰命名
    • react 的事件处理函数就是一个函数,不是字符串
    • 事件处理函数没有绑定 this,需要我们自己绑定 this
    class MyHome extends React.PureComponent {
      constructor() {
        super();
        this.clickHandler = this.clickHandler.bind(this);
      }
      clickHandler(e) {
        console.log(this);
        console.log(e);
        // 这个e不是原生的事件对象,是经过react加工的,叫做合成事件,解决了兼容性问题
      }
      render() {
        return (
          <div>
            <h1 onClick={this.clickHandler}>thisundefined,e是合成事件</h1>
            <h1
              onClick={(e) => {
                this.clickHandler(e);
              }}
            >
              this是组件实例对象,需要在箭头函数中获取合成事件,作为实参传递下去
            </h1>
            <h1 onClick={this.clickHandler}>this是组件实例对象,也有事件对象传入</h1>
          </div>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    12 非受控组件 - 不推荐

    • 没有设置表达的受控属性的值,就是非手动组件
    • 非受控组件通过 dom 操作来获取表单元素的值

    13 受控组件 - 推荐

    • 设置了受控属性的值,就是受控组件
    • 可以受控的表单属性主要有
      • value: text,password,color,select,…
      • checked: radio,checkbox
    • 受控组件通过设置受控属性的值,和 onChange 事件来设置和获取表单元素的值
    • 如果手动属性是 value,我们一般写成:
    class MyForm extends React.PureComponent {
      constuctor() {
        super();
        this.state = {
          name: "",
        };
      }
      changeHandler(e, key) {
        this.setState({
          [key]: e.target.value,
        });
      }
      render() {
        const { name } = this.state;
        return (
          <div>
            <input
              type="text"
              value={name}
              onChange={(e) => this.changeHandler(e, "name")}
            />
          </div>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 如果受控的属性是 radio 的 checked,但是我们需要的数据是 value
    class MyForm extends React.PureComponent {
      constuctor() {
        super();
        this.state = {
          gender: "man",
        };
      }
      changeHandler(e, key) {
        this.setState({
          [key]: e.target.value,
        });
      }
      render() {
        const { gender } = this.state;
        return (
          <div>
            <input
              type="radio"
              value="man"
              checked={gender == "man"}
              onChange={(e) => this.changeHandler(e, "gender")}
            /><input
              type="radio"
              value="woman"
              checked={gender == "woman"}
              onChange={(e) => this.changeHandler(e, "gender")}
            /></div>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 如果受控的属性是 checkbox 的 checked,但是我们需要的数据是 value 的集合
    class MyForm extends React.PureComponent {
      constuctor() {
        super();
        this.state = {
          love: ["football", "basketball"],
        };
      }
      changeHandler(e,key) {
        const {value,checked} = e.target
        this.setState((state)=>{
          [key]:checked?[...state.love,value]:state.love.filter(item=>item!=value)
        })
      }
      render() {
        const { love } = this.state;
        return (
          <div>
            <input
              type="checkbox"
              value="football"
              checked={love.includes("football")}
              onChange={(e) => this.changeHandler(e, "love")}
            />
            足球
            <input
              type="checkbox"
              value="basketball"
              checked={love.includes("basketball")}
              onChange={(e) => this.changeHandler(e, "love")}
            />
            篮球
            <input
              type="checkbox"
              value="waterfall"
              checked={love.includes("waterfall")}
              onChange={(e) => this.changeHandler(e, "love")}
            />
            水球
          </div>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    14 状态提升

    • 如果多个组件之间要共享状态,把状态提升到共同的父组件中声明
    • 如果要在子组件中修改父组件的状态,需要父组件通过 props 传递修改状态的方法给子组件,传递方法的时候要 bind 父组件的 this
    // 子组件
    class Input extends React.PureComponent(){
      changeFatherState(){
        const {changeList} = this.props
      }
      // 修改父组件的状态
      render(){
        return ()
      }
    }
    // 子组件
    class List extends React.PureComponent(){
      // 子组件通过props接收父组件的数据
      render(){
        const {data} = this.props
        return ()
      }
    }
    
    class Todos extends React.PureComponent(){
      constructor(){
        super()
        this.state = {
          list:[]
        }
      }
      changeList(){
        // 这个方法可以修改list
      }
      render(){
        return <>
          <Input changeList={this.changeList.bind(this)}/>
          <List data={list}/>
        </>
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    15 context

    • 可以通过 React.createContext 创建一个上下文对象,比如:MyContext
      • 语法:React.createContext(上下文对象的默认值)
    • 任意类组件可以通过: 组件名.contextType = MyContext,来使用 MyContext 这个上下文对象
    • 在类组件内部通过:this.context 来获取上下文对象
    • 如果前面的祖先没有通过 value 来给 MyContext 赋值,我就用 MyContext 的默认值
    • 可以通过MyContext.Provider组件的 value 属性来给 MyContext 赋值
      • 赋值会完全覆盖默认值,只影响当前组件的子子孙孙
    • 如果有多个 MyContext.Provider 设置 value 属性,使用最近的

    16 Portal

    • 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案
    • 就是使用 react-dom 包里面的 createPortal 方法
    • 语法:createPortal(react 元素,要插入到的 dom 节点)

    17 Refs&DOM

    • refs 提供了一种获取 dom 节点和 react 元素的方法
    • 方法 1: React.createRef()
    class MyHome extends React.PureComponent {
      constructor() {
        super();
        // 步骤1: 通过React.createRef()创建一个refs
        this.myRef = React.createRef(); // {current:null}
      }
      componentDidMount() {
        // 当组件挂载完成后,this.myRef = {current:dom节点}
      }
      render() {
        return (
          <div>
            {/* 步骤2:附加到html原生标签上 */}
            <input type="text" ref={this.myRef} />
            {/* 如果附加到组件标签上,那么this.myRef  = {current:组件实例对象} */}
          </div>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 方法 2: 回调 refs - 即可以绑定也可以解绑
    class MyHome extends React.PureComponent {
      constructor() {
        super();
        this.handler = (val)=>{
          // 把实参的dom元素或者组件实例给其他方法使用
          this.myInput = val;
        }
      }
      render() {
        return (
          <div>
            {/* ref的值是一个函数,这个函数会在组件挂载完成的时候传入实参,就是当前附加ref的dom元素或者组件实例,当组件卸载的时候,会传入实参null */}
            <input type="text" ref={} />
          </div>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    18 refs 转发

    • 将 ref 自动地通过组件传递到其一子组件的技巧
    • 重用的组件库是很有用的
    • 一般组件库里面的哪些组件会有 refs 转发:Input,Button,…
    • 这些组件倾向于以一种类似常规 DOM button 和 input 的方式被使用,并且访问其 DOM 节点
    const Input = React.forwardRef((props, ref) => {
      // React.forwardRef()
      // ()里面是一个函数组件,这个函数组件在被React.forwardRef调用的时候
      // 会传入两个参数,第一个是props
      // 第二个是要转发的ref,可能是当前组件的子组件,也可能是当前组件内的dom几点
      return <input type="text" {...props} ref={ref} />;
    });
    
    class MyHome extends React.PureComponent {
      constructor() {
        super();
        this.input = React.createRef();
      }
      componentDidMount() {
        // this.input.current其实就是Input组件里面的input那个dom节点
        this.input.current.focus();
      }
      render() {
        return (
          <div>
            <h1>MyHome</h1>
            <Input ref={this.input} />
          </div>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    19 高阶组件

    • 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧
    • 高阶组件: 是一个函数,参数是一个组件,返回值也是一个组件
    • 高阶组件不是组件时函数
    • 通过高阶组件可以给组件添加一些额外的信息

    20 hooks

    • useState
    const [count, setCount] = useState(0);
    // 不依赖上次的
    setCount(10);
    // 依赖上次的
    setCount((count) => count + 10);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • useEffect
    useEffect(() => {
      // didMount
      return () => {
        // willUnmount、didUpdate
      };
    }, [count]);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • useMemo
    const double = useMemo(() => {
      return count * 2;
    }, [count]);
    
    • 1
    • 2
    • 3
    • useCallback
    const fn = useCallback(() => {
      console.log(count);
    }, [count]);
    
    • 1
    • 2
    • 3
    • useRef
    const myRef = useRef("inp"); // {current:'inp'}
    
    • 1
    • useContext
    const myContext = useContext(ThemeContext);
    
    • 1
  • 相关阅读:
    【Vue】基础语法(创建项目|数据绑定|事件绑定|声明方法|插值表达式|属性值绑定|循环数组|v-if控制||计算属性|监听器|过滤器)
    【JAVA并发】一、并发问题产生的根源
    36 - 新的 Promise 方法:allSettled & any & race
    LeetCode常见题型——链表
    Sunlogin RCE漏洞分析和使用
    精通HTML页面的生命周期
    《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(20)-Fiddler精选插件扩展安装,让你的Fiddler开挂到你怀疑人生
    基于springboot的家政系统 毕业设计-附源码201524
    ✔ ★【备战实习(面经+项目+算法)】 10.25学习(算法刷题:5道)
    【C++】继承 ③ ( 继承的一些重要特性 | 子类拥有父类的所有成员 | 多态性 | 子类可以拥有父类没有的成员 | 代码示例 )
  • 原文地址:https://blog.csdn.net/weixin_58764638/article/details/127718379