• React 的函数组件


    写在前面

    React 的函数组件是 React 组件的另一种定义方式,两种方式都可以用于定义组件,但是相比于类组件,函数组件要更简单好用些。

    组件名一般要大写,是为了在组件使用时与一般的 html 标签区分开

    1. 创建方式

    函数组件的创建方式就是定义一个函数,这个函数 return React组件。因此,返回一个 React 元素的函数就是组件。在 ES6 语法中,函数有两种定义方式,普通函数和箭头函数,因此,函数组件的方式也是两种。

    const Hello = () => {
          return <div>Hello Word</div>
    }
    
    function Hello(){
          return <div>Hello Word</div>
    }
    

    2. 外部数据 props

    函数接收外部数据的方式就是在函数的参数里拿到,如下:

    const Hello = (props) => {
          return <div>{props.msg}</div>
    }
    

    3. 内部数据 state

    函数组件没有 state,React v16.8.0 推出了 Hooks API,提供了 React.useState API解决了此问题。

    函数组件的 state 数据的设置和获取是提供了一个接口 React.useState(初始值),用于设置 state 的初始值,对 state 进行初始化。函数里面的参数为初始值,函数返回一个数组,数组的第一个是读数据方式,第二个是写数据方式。读数据变量命名为 xx 时,写数据方式一般命名为 setXX。

    const Welcom = ()=>{
      const [n,setN] = React.useState(0);//析构赋值
      //等价于
      /*
      const state = React.useState(0);
      const n = state[0];
      const setN = state[1];
      */
      return (
        <div className="wel">
        n: {n}
    		<button onClick={()=>setN(n+1)}>+1</button>
        </div>
      )
    }
    

    或者是先引入 useState,后面就不用再加 React. 了

    import React, { useState } from 'react';
    const Welcom = ()=>{
       const [n,setN] = useState(0);
    }
    

    同样的,setN 也是一个异步函数,不会立马执行。和 setState 不同的是,setState 是等一会后会改变 state ,而 setN 是永远不会改变 n,而是产生新的 n。

    函数组件的 state 的写和 class 类组件的写是完全不同的,函数组件的 setState 不会自动合并之前的值。如下:

    const A = ()=>{
          const [user,setUser] = React.useState({name: 'jack', age: 18});
          const onChangeName = ()=>{
                setUser({
                      //必须加上这一句拷贝之前的数据: ...user,
                      name: 'lisa'    //这样写是完全错误的,不会自动合并之前的 state
                })
          }
          return (
                <div className="App">
                      <h1>{user.name}</h1>
                      <h1>{user.age}</h1>
                      <button onClick={onChangeName}>change name</button>
                </div>
          )
    }
    

    而且,函数组件的 setState 在接受同一个 state 对象时,即使其对象里的属性变了,但对象地址没变,是不会更新视图的。

    const A = ()=>{
          const [user,setUser] = React.useState({name: 'jack', age: 18});
          const onChangeName = ()=>{
                user.name = 'lisa',
                setUser(user)   //错误,React 发现接收的对象的地址是同一个,则会认为数据没有改变,不会更新视图
          }
          return (
                <div className="App">
                      <h1>{user.name}</h1>
                      <h1>{user.age}</h1>
                      <button onClick={onChangeName}>change name</button>
                </div>
          )
    }
    

    应该产生一个新的 state 对象传入:

    const onChangeName = ()=>{
                setUser({
                      ...user,
                      name: 'lisa'
                })   
          }
    

    函数中的 setState 注意事项:

    1. 不可局部更新视图

    2. 地址一定要变

    4. 函数组件模拟生命周期

    函数组件同样地没有生命周期,但是 React Hooks API 提供了 React.useEffect 来解决此问题。

    React.useEffect(fn, ??) 第一个参数是在特定时机到的时候执行的回调函数,第二个参数是指明什么时机。

    4.1 模拟 componentDidMount 第一次渲染

    在第二个参数为 [] 时只会在第一次渲染时执行

    useEffect(()=>{
          console.log("第一次渲染");
    },[])
    

    4.2 模拟 componentDidUpdate (不完全模拟)

    在第二个参数的数组里加上要监听变化的数据就行,若不加数组,不传第二个参数,则会在 state 的任意一个属性改变时都会触发该函数回调

    useEffect(()=>{
          console.log("n 变了");
    },[n])
    
    useEffect(()=>{
          console.log("任意属性变了");
    })
    

    但是这样的模拟并不完全等同,因为该函数回调会在一开始在数据由未定义 undefined 到被赋值后会执行该回调函数。而 componentDidUpdate 不会再第一次渲染时执行。

    因此可以 自定义 Hook 进行计数,正确模拟 componentDidUpdate 钩子,自定义 useUpdate.js 如下:

    const useUpdate = (fn, dep)=>{
          const [count,setCount] = useState(0)
          useEffect(()=>{
                setCount(x => x + 1);
          },[dep])
          useEffect(()=>{
                if(count > 1){
                      fn()
                }
          },[count,fn])
    }
    

    4.3 模拟 componentWillUnmount

    模拟销毁前执行时期,是用函数里返回函数的方式。

    useEffect(()=>{
          console.log("任意属性变了");
          return ()=>{
                console.log("该组件要销毁了")
          }
    })
    

    4.4 其他组件的模拟

    constructor 钩子的模拟就是在函数组件中,return 语句前的所有语句,这些语句都是在初始化函数组件的数据。

    render 钩子就是函数组件中 return 返回的内容

  • 相关阅读:
    leetcode面试准备:Kth Largest Element in an Array
    leetcode面试准备:Minimum Size Subarray Sum
    leetcode面试准备:Valid Anagram
    leetcode面试准备:Divide Two Integers
    leetcode面试准备:Container With Most Water
    面试:归并排序和分治法
    leetcode面试准备:Lowest Common Ancestor of a Binary Search Tree & Binary Tree
    Leetcode解题思想总结篇:双指针
    leetcode面试准备: CountPrimes
    RF中BDD编写
  • 原文地址:https://www.cnblogs.com/lovevin/p/13231718.html
Copyright © 2020-2023  润新知