React学习笔记 - 函数组件

180 阅读1分钟

一、创建

const App = (props)=>{
    return <div>{props.message}</div>
}

函数组件的问题:

  • 没有 state ---- React v16.8.0 推出 Hooks API,用useState解决
  • 没有生命周期 ---- Hooks API,用useEffect解决

二、state

使用useState

const App = props => {
    const [n, setN] = React.useState(0)
    return //...
}

三、生命周期

使用useEffect

useEffect接收两个参数:useEffect(fn, arr)

1、模拟 componentDidMount

useEffect(fn, []) //第二个参数为空数组,仅在第一次渲染后调用fn

2、模拟 componentDidUpdate

useEffect(fn, [n, m]) //第一次渲染,以及数组内的数据变化,调用fn
useEffect(fn) //第一次渲染,以及任何数据变化均会调用fn

问题:这样写第一次渲染时也会调用fn,如何实现仅在数据更新后才调用?

解决:在fn中加入条件判断,用一个变量记录n更新的次数,次数>1,再执行操作

const [nUpdateCount, setNUpdateCount] = useState(0)

useEffect(()=>{
    setNUpdateCount(x=>x+1)
}, [n])
useEffect(()=>{
    if(nUpdateCount > 1){
        console.log('n变了')
    }
}, [nUpdateCount])

优化:自定义一个Hook,将上述代码封装为一个useUpdate函数,useUpdate(fn, n)表示仅当n更新时调用fn

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

3、模拟 componentWillUnmount

useEffect(fn)fn返回的函数会在组件销毁时执行,即:

useEffect(()=>{
    return ()=>{/* ... */}
})

【例】

模拟一个组件被销毁的场景,点击按钮销毁子组件Child:

const App = props => {
  const [childVisible, setChildVisible] = React.useState(true)
  const show = ()=>{setChildVisible(true)}
  const hide = ()=>{setChildVisible(false)}
  return (
    <div>
      {childVisible?
		<button onClick={hide}>隐藏</button>:
		<button onClick={show}>显示</button>}
      {childVisible?<Child />:null}
    </div>
  )
}

const Child = props => {
  useEffect(()=>{
    return ()=>{console.log('child销毁了')}
  })
  return (
    <div>我是child</div>
  )
}

4、模拟 shouldComponentUpdate

React.memouseMemo,详见后续