「React」React全解-函数组件

241 阅读2分钟

1.创建方式

const Hello = (props)=>{
 return <div>{props.message}</div>
}//1
const Hello = props =><div>{props.message}</div>//2
function Hello(props){
 return <div>{props.message}</div>
}//3

2.没有state怎么办

React v16.8.0 推出Hooks API
其中有个API叫做useState

const App = props = {
 const [n,setN] = useState(0)//n为读,setN为写
 const onClick = () => {
  setN(n + 1)
 }
 return (
  <div>
    {n}
    <button onClick={onClick}>+1</button>
  </div>
 )
}

3.没有生命周期怎么办

所谓的生命周期就是在特定的函数里做某件事
React v16.8.0 推出 Hooks API
其中一个API叫做useEffect,解决副作用
模拟componentDidMount

import React, { useState, useEffect } from 'react'
// 所有都用箭头函数,消除了this
//模拟componentDidMount
const App = props => {
    const [n, setN] = useState(0)
    const onClick = () => { setN(n + 1) }
    useEffect(() => { console.log('use effect') }, [])
    return (
        <div>{n}
            <button onClick={onClick}>1</button>
        </div>
    )
}
export default App
模拟componentWillUnmount
import React, { useEffect, useState } from 'react'
// 所有都用箭头函数,消除了this
const App = props => {
    const [childVisible, setChildVisible] = useState(true)
    const hide = () => {
        setChildVisible(!childVisible)
    }
    const show = () => {
        setChildVisible(!childVisible)
    }
    console.log(!childVisible)
    useEffect(() => { console.log('use effect') })
    return (
        <div>
            {childVisible ? <button onClick={hide}>hide</button> : <button onClick={show}>show</button>}
            {childVisible ? <Child /> : null}
        </div>
    )
}
//onClick 只接受函数,不接受函数调用
const Child = (props) => {
    useEffect(() => {
        return () => {
            console.log('Child 销毁了')
        }
    })
    return (<div>Child</div>)
}
export default App

生命周期总结

  • 模拟componentDidMount
    useEffect(()=>{console.log('第一次渲染'),[]})
  • 模拟componentDidUpdate, 在某个东西变化了之后执行的代码,但第一次渲染也会触发
    useEffect(()=>{console.log('任意属性变更,后面的数组可以不写')})
    useEffect(()=>{console.log('n变了'),[n]}) //依赖于n改变
    useEffect(()=>{console.log('n或者m变了'),[n,m]})
  • 模拟componentWillUnmount
 useEffect(()=>{
 console.log('第一次渲染')
  return ()=>{
   console.log('组件要死了')
  }
})
  • constructor
    函数组件执行的时候,就相当于constructor
  • shouldComponentUpdate
    后面的React.memo和useMemo可以解决
  • render
    函数组件的返回值就是render的返回值

4.自定义hook之useUpdate

场景:解决对第一次渲染也触发上述模拟componentDidUpdate这个的执行代码,下面三种方式是对这项功能的优化过程,也可以只看useUpdate用法。
第一次由undefined变为0时不执行函数
第二次变化时,执行函数
第三次变化时,执行函数
。。。

实现修改才触发钩子

// 实现修改才触发钩子
import React, { useEffect, useState } from 'react'
const App = props => {
    const [n, setN] = useState(0)
    const onClick = () => {
        setN(n + 1)
    }
    const [nUpdateCount, setNUpdateCount] = useState(0)
    useEffect(() => {
        setNUpdateCount((nUpdateCount) => nUpdateCount + 1)
    }, [n])
    useEffect(() => {
        if (nUpdateCount > 1) {
            console.log(nUpdateCount)
            console.log("修改了n")
        }
    }, [nUpdateCount])
    return (
        <div>
            {n} <button onClick={onClick}>+1</button>
        </div>
    )
}
export default App

用组件封装起来

// 实现修改才触发钩子
import React, { useEffect, useState } from 'react'

const App = props => {
    const [n, setN] = useState(0)
    const onClick = () => {
        setN(n + 1)
    }

    const useX = (n) => {
        const [nUpdateCount, setNUpdateCount] = useState(0)
        useEffect(() => {
            console.log("修改了n")
            setNUpdateCount((nUpdateCount) => nUpdateCount + 1)
        }, [n])
        return { nUpdateCount }

    }
    const nUpdateCount = useX(n).nUpdateCount
    // console.log(nUpdateCount)
    useEffect(() => {
        if (nUpdateCount > 1) {

            console.log("修改了nUpdateCount")
        }
    }, [nUpdateCount])
    return (
        <div>
            {n} <button onClick={onClick}>+1</button>
        </div>
    )
}


export default App

引入和使用自定义的useUpdate(最终版)


import React, { useEffect, useState } from 'react'

const useUpdate = (fn, n) => {
    const [count, setCount] = useState(0)
    // console.log(nUpdateCount)
    useEffect(() => {
        // console.log("修改了n")
        setCount((count) => count + 1)
    }, [n])


    useEffect(() => {
        if (count > 1) {
            fn()
        }
    }, [count, fn])

// 疑问?????依赖fn是控制台提示写的,但是点击按钮就触发了两次

}

const App = props => {
    const [n, setN] = useState(0)
    const onClick = () => {
        setN(n + 1)
    }


    useUpdate(() => {
        console.log("修改了nUpdateCount")
    }, n)
    return (
        <div>
            {n} <button onClick={onClick}>+1</button>
        </div>
    )
}

export default App

5.class组件生命周期例子