【React初接触】(三)useState & useEffect

879 阅读2分钟

「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

【前情】在 class 组件中使用 state

class Layout extends React.Component {
    state = {
        loading: true
    }
    
    componentDidMount() {
        this.setState({ loading: false })
    }
    
    render() {
        const { loading } = this.state;
        const { children, isLogin } = this.props;
        if (!isLogin || loading) {
            return (
                <div>loading...</div>
            )
        }
        return ( children )
    }
}

使用 hook

实现在不编写 class 组件 的情况下使用 state 以及其他 react 特性

一个组件中多次调用 useState and useEffect,是完全独立的

useState

在函数组中修改组件状态。具体说明参考:【React初接触】(二)粗了解State和prop

const [state, setState] = useState(initialVal);

import { useState } from 'react';

export default (props?: any) => {
    // useState 传入初始state参数,返回当前 state 和 更新state的函数
    const [count, setCount] = useState(() => {
        return someExpensiveComputation(initialCount);
    })
    
    return (
        Count: {count}
        
        // 传参形式一:setCount 传入更新值
        <button onClick={() => { setCount(initialCount) }}>reset</button>
        
        // 传参形式二:setCount 传入函数
        <button onClick={() => setCount(preCount => preCount - 1)}> - </button>
        <button onClick={() => setCount(preCount => preCount + 1)}> + </button>
    )
}

useEffect

副作用操作:数据获取、设置订阅、手动更改React组件中的DOM

useEffect(didUpdate)

react更新 DOM 之后运行一些额外的代码,通过这个hook 告知组件操作内容。React 会保存这个函数(effect),并在执行 DOM 更新之后调用。

  1. 执行时机:
  • 默认情况: 第一次渲染之后 和 每次更新之后 都会执行(保证每次执行,DOM都已经更新完成,即在浏览器完成布局和绘制之后)。

  • 条件执行:useEffect 传递第二个参数,作为依赖值数组,其中任意项变化都将触发函数调用

    p.s. 确保数组包含所有外部作用域中会随时间变化并且在effect中使用的变量,否则代码会引入之前的变量。

  • 特殊用法:useEffect 第二个参数是空数组时,将只在组件挂载和卸载时执行一次

    effect 不依赖 propsstate,故不需要重复执行。

// 仅在count更改时更新
useEffect(() => {
    document.title = `you click ${count} times`;
}, [count])

// 仅在组件挂载时更新
useEffect(() => {
    document.title = `you click ${count} times`;
}, [])
  1. 清除:
  • 无需清除的 effect

  • 需要清除的 effect:返回清除函数,将在下一个 effect 执行之前清除上一个

使用 useEffect 解决一个常见报错

Warning: Can't perform a React state update on an unmounted component.

This is a no-op, but it indicates a memory leak in your application.

To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

解决方法:在组件未渲染时操作state产生报错(常见于setTimeout操作等)

  1. class组件使用 componentWillUnmount
  componentWillUnmount(){
    clearTimeout(id)
  }
  1. useEffect传入清除函数
const [isOnline, setIsOnline] = useState(null)

useEffect(() => {
    const id = setTimeout(() => {...})
    return () => {
        clearTimeout(id)
    }
}