1. 创建方式

 //  写法一
const Hello = (props) => {      
    return <div>{props.message}</div>
}

 //  写法二
const Hello = props => <div>{props.message}</div>  

// 写法三
function Hello(props) {
    return <div>{props.message}</div>
}

2. 函数组件代替类组件

面临的问题

  • 函数组件没有state => React v16.8.0推出Hooks API,其中的一个API叫做useState可以解决问题
  • 函数组件没有生命周期 => React v16.8.0推出Hooks API,其中的一个API叫做useEffect可以解决问题

我们对比一下两种组件实现 n + 1 的例子

类组件

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            n: 0
        }
    }

    addNum = () => {
        this.setState({n: this.state.n + 1})
    }

    render() {
        return (
            <div className='App'>
                <span>n:{this.state.n}</span>
                <button onClick={this.addNum}>n+1</button>
            </div>
        )
    }
}

函数组件

const App = props => {
    const [n,setN] = React.useState(0)
    function addNum(){
        setN(n + 1)
    }
    return (
        <div className='App'>
            {n}
            <button onClick={addNum}>+1</button>
        </div>
    )
}

相比之下函数组件更为简洁一些

使用 useEffect 解决生命周期问题

  1. 模拟 componentDidMount 首次渲染
useEffect(() => {     //  模拟componentDidMount  首次渲染
        console.log('use effect')
    },[])    // 空数组必须写
  1. 模拟 componentDidUpdate
const [n, setN] = React.useState(0)
useEffect(() => {     //  模拟  componentDidUpdate 
        console.log('n 变化了')
    },[n])  // 数组里面可以写多个参数表示监听多个变量

useEffect(() => {     //  模拟  componentDidUpdate 
        console.log('任意属性变更了')
    })  // 不写数组表示监听所有 useState  的变量
//  但是这样在第一次渲染时也会触发函数的执行  
 解决方法使用自定义Hook 见下一标题
  1. 模拟componentWillUnmount
  useEffect(() => {    
        return () => {
            console.log('Child 销毁了')
        }
    })    //  返回一个函数 在销毁时执行
  1. constructor
    函数组件执行的时候,就相当于constructor

  2. shouldComponentUpdate
    后面的 React.memo和useMemo可以解决

  3. render
    函数组件的返回值就是render的返回值.

//  模拟render里面写逻辑
const X = (props) => {
    console.log('我是要写的逻辑')
    return (
        <div>逻辑模拟</div>
    )
}

const App = props => {
    let [childVisible, setChildVisible] = useState(true)

    const changeVisible = () => {
        setChildVisible(!childVisible)
    }

    return (
        <div className='App'>
            {childVisible ? <button onClick={changeVisible}>{childVisible}</button> :
                <button onClick={changeVisible}>hide</button>}
            {/*{childVisible ? <Child/> : null}*/}
            <Child/>
            <X/>     
        </div>
    )
}   // 一个函数便是一个组件

3. 自定义 Hook 之 useUpdate
解决上面 n 值初次渲染就执行的问题

const App = props => {
    const [n, setN] = useState(0)
    const onClick = () => {
        setN(n + 1)
    }
    const [nUpdateCount, setNUpdateCount] = useState(0)
    useEffect(() => {    // 初次渲染就执行 + 1
        setNUpdateCount(nUpdateCount + 1)
    }, [n])
    useEffect(() => {    // 初次渲染就执行 判断是否大于1 
        if(nUpdateCount > 1){
            console.log('n变了')
        }
    },[nUpdateCount])
    return (
        <div className='App'>
            n值变成了:{n}
            <button onClick={onClick}>n+1</button>
        </div>
    )
}
//  通过使用两次 useEffect 第一个触发第二个 useEffect 函数计数,大于0便是n值变化了

上面的代码很乱 改进一下

const useX = (fn, dep) => {   // 这就是自定义 Hook 这就可以抽离成别的文件
    const [count, setCount] = useState(0)
    useEffect(() => {
        setCount(x => x + 1)
    }, [dep])
    useEffect(() => {
        if (count > 1) {
            fn()
        }
    }, [count,fn])
}

const App = props => {
    const [n, setN] = useState(0)
    const onClick = () => {
        setN(n + 1)
    }
    useX(() => {
        console.log('n 变化了')
    }, n)
    return (
        <div className='App'>
            n值变成了:{n}
            <button onClick={onClick}>n+1</button>
        </div>
    )
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐