四、React 函数式组件及常用的hooks

1. 函数式组件

函数式组件默认return出组件模板

javascript 复制代码
import './App.css';
import React from 'react';

function App(props) {
  return (
    <div>
      hello react.js
    </div>
  );
}

export default App;

函数式组件的特点:

  • 1.没有组件状态
  • 2.没有生命周期函数
  • 3.没有this,不能实例化
  • 4.每次组件更新,当前函数都会执行一次。

函数式组件跟类组件的区别:

  • 函数式组件内this值是undefined,不能当作当前组件实例来使用。可以通过函数调用来渲染。
  • 函数式组件内部默认没有状态。
  • 函数式组件内部没有生命周期。

2. hooks

useState: 用来定义组件状态,将需要定义的数据通过函数参数传递进去,返回值是一个数组,数组的第一个元素是定义的状态,第二个元素是一个函数,用来更新组件状态。

第二个参数触发组件更新,其实是重新调用函数式组件,所有组件内部的所有代码都会重新执行。

对于引用类型的值,在通过第二个参数更新的时候,需要深拷贝一下。

javascript 复制代码
import './App.css';
import React, { useState } from 'react';

function App(props) {

  var [count, setCount] = useState(0);  //用来定义组件内部的状态

   //当定义的状态是引用类型的时候需要注意,引用类型指向的是存储地址,所以将新的值传递给set函数去更新的时候,他会认为没有改变,就不会更新组件,这时候可以深拷贝一下。
  var [arr, setArr] = useState([]); 

  var handlechange = () => {
    // 修改组件状态
    setCount(count + 1)
  }

  var handlechangeArr = () => {
    arr.push(parseInt(Math.random() * 10))
    setArr([...arr])
  }

  return (
    <div>
      <h1>函数式组件</h1>
      <div>{count}</div>
      <div>arr:{arr}</div>
      <button onClick={handlechange}>改变状态</button>
      <button onClick={handlechangeArr}>改变数组的值</button>
    </div>
  );
}

export default App;

useEffect:

用来给函数式组件添加生命周期方法。

它可以看做是 componentDidMount,componentDidUpdate和componentWillUnumount这三个生命周期函数的组合。

当useEffect函数的参数是一个回调函数时它类似于类组件中的componentDidUpdate方法,在组件每次更新的时候都执行。在参数的回调函数内return出一个函数,就会在组件卸载的时候调用,类似于类组件中的componentWillUnmount,可以用释放造成副作用的代码。

当useEffect函数的第一个参数是一个函数,第二个参数放一个空数组的时候,类似于类组件中的componentDidMount方法,在组建初次挂载的时候执行一次。数组里面也可以监听组件状态的变化,当所将领的组件状态发生改变的时候,执行回调函数。

javascript 复制代码
import React, { useState, useEffect } from 'react';

  // 模仿类组件的生命周期函数
  //这样的写法类似于类组件中的componentDidUpadte,在组件初次渲染和更新的时候都会执行
  useEffect(() => {
    console.log('组件更新了')
  })

  // 这样的写法类似于类组件中的componentDidMount,在组件初次渲染的时候执行,只执行一次
  useEffect(() => {
    console.log('组件挂在了')
    // 可以在这里发送请求,做事件监听,创建定时器等
    
    //在组件卸载的时候调用执行
    return ()=>{}
  }, [])

  // 这种写法会监听数组中的数据,当数据发生变化的时候才会执行回调函数(初次渲染也会执行)
  useEffect(() => {
    console.log('count发生了变化')
  }, [count]) //也可以监听多个值

useRef

用来定义一个ref引用,通过ref绑定到dom节点身上,可以获取到dom节点。

javascript 复制代码
  import React, {  useRef } from 'react';

  var myref = useRef()
  
  return (
    <div>
      <h1 ref={myref}>函数式组件</h1>
    </div>
  );

useContext: 用来接收组件通信中跨组件通信传递过来的值。由于函数式组件中没有this,所以需要用来useContext来接收。

javascript 复制代码
import React, { useContext } from 'react';
import context from '../utils/context';

function Child2(props) {
    var count = useContext(context)
    return (
        <div className='child2' style={{ border: '1px solid yellow', padding: '10px' }}>
            {/* 内层组件将context绑定给组件的contextType,然后组件内部通过this.去使用
                但是现在函数式组件没有this,所以需要用react提供的 useContext hook去接收
            */}
            {/* <h1>child2-{this.count}</h1> */}
            <h1>child2-{count}</h1>
        </div>
    );
}

// Child2.contextType = context;

export default Child2;

组件更新导致的重新计算: 由于组件状态更新的时候会导致函数式组件内部代码重新执行一遍,所以如果组件内部有耗时庞大的任务时,就会导致不必要的执行,可以通过useMemo去优化。

useMmemo

第一个参数是一个回调函数,会将第一个回调函数的返回值作为useMemo的返回值缓存起来。

第二个参数是一个数组,里面可以放需要监听的参数。

当监听的值发生改变的时候,才会去执行回调函数并将返回的结果缓存起来。如果没有发生变化,会直接将缓存的结果返回。

javascipt 复制代码
import {useMemo} from 'react'

var result = useMemo(()=>{},[])

memo高阶组件

当父组件里面渲染子组件的时候,改变父组件状态,会导致子组件跟着更新。当子组件内部没有依赖父组件传递的数据的时候就没必要更新。

memo是一个高阶组件,它类似于类组件中的pureComponent,会对props做一个浅层比较。根据比较结果来决定是否更新子组件。

javascript 复制代码
import  React, {memo} from 'react'

function Child(props){
    var {count} = props;
    return (
        <div className='chils'>
            {count}
        <div/>
    )
}

export default memo(Child)

useCallback

如果父组件传递一个函数到子组件的时候,当父组件更新时子组件也会更新,因为函数是一个引用类型,他每次重新创建的地址都是不同的,所以子组件内部比较的时候,每次都是不一样的props。

可以借助 useCalback 钩子函数来做优化。来缓存函数定义,他只会在组件挂载的时候执行一次。这样就不会导致子组件重新更新。 原理:通过缓存第一个参数回调函数,来实现性能优化的。他的返回值是第一个参数。如果第一个参数也需要做复杂耗时的任务,也可以把需要依赖的值放在第二个参数的数组里面。当第二个参数依赖的值没有发生变化,就不会重新定义。

javascript 复制代码
import React ,{useCallback} from 'react'

function App(props){
    var saveIndex = useCallback(()=>{
        console.log("传递给子组件的函数")
    },[])
    return (
        <div>
            <Child callback = {saveIndex}/>
        <div/>
    )
}

export default App;

hooks使用规则

hook的本质就是一个javascript函数,在使用它的时候需要遵循两条规则:

只在最顶层使用hook: 不要再循环,条件或嵌套函数中调用hook。确保你总是在顶层使用hook。

只在react函数中使用hook: 不要普通的js函数中调用。

  • 在函数式组件中去调用。
  • 在自定义hook中去调用。

3.自定义hook

将高度耦合通用性比较高的代码封装到一个hook中,hook命名一般是以use开头。

javascript 复制代码
import {useEffect,useState} from 'react'

// 封装一个自定义hook
export function useRequest(){
    var [list,setList] = useState([])
    useEffect(()=>{
        // 发请求去获取数据
    },[])

    return [list,setList]
}
相关推荐
@大迁世界14 分钟前
停止在 React 组件回调中使用箭头函数!
前端·javascript·react.js·前端框架·ecmascript
stonefisher5 小时前
深挖`React`里程碑之作`AutoStore`与`helux`的渊源
前端·react.js·前端框架
liangshanbo12157 小时前
创建可重用React组件的实用指南
前端·javascript·react.js
Dragon Wu11 小时前
前端框架 react 性能优化
前端·javascript·react.js·性能优化·前端框架·react
PleaSure乐事14 小时前
JS/JSP/JSX的区别与关联
前端·javascript·react.js·前端框架·jsp·jsx
GISer_Jing1 天前
从0开始分享一个React项目:React-ant-admin
前端·react.js·前端框架
刺客-Andy1 天前
React第六节 组件属性prop的propTypes类型使用介绍
前端·javascript·react.js·typescript
刺客-Andy1 天前
React第四节 组件的三大属性之state
前端·javascript·react.js
黄毛火烧雪下1 天前
React 表单Form 中的 useWatch
前端·javascript·react.js