React 组件
React 组件是什么?如何构建一个 React组件。
react 中组件的形式有两种 函数组件以及类组件,函数组件很好理解只要最终返回一个虚拟树就可以了,这中间的逻辑完全就是 js 的逻辑,没有什么好记录的,但类组件涉及到父类以及 state 需要记录一下。
类组件
state
state 可以说是 react 实现数据变化更新视图的最重要的一部分。
state 干嘛用?
state 表示一个组件的内部可变数据的集合,为什么说是可变的数据呢?
不变的数据用 this 保存即可,因为不会发生变化,所以不用触发视图更新。
没了,作用就是保存数据。那么如何触发视图更新呢?
这就需要用到 setState 。
setState 是什么?
setState 是一个函数,该函数接收一个对象或接收一个函数。
setState 做了什么?
this.setState({...})
执行之后发生了什么?总的来说,有以下步骤:
- 获取原先 
state保存的数据:prevState - 将传入的对象合并到 
prevState生成:nextState - 将 
this.state = nextState - 通知虚拟树的根组件重新生成虚拟树(调用函数组件或是类组件的 
render方法) - 将新的虚拟树与之前的虚拟树作对比(
diff算法),找出差别,生成更新程序(patch) - 执行更新程序 
html页面需要更新的地方就会发生变化 
setState 参数为函数的情况
this.setState((prevState, props) => ({...}))
与对象形式的 setState 区别在于第三点,函数形式为
- 将 
this.state = 函数调用的结果 
setState 的内容是异步执行
以上不管是对象形式还是函数形式,上面所说的 6 步都会异步执行。
this.state = {a: 1};
this.setState({a: this.state.a + 1})
this.setState({a: this.state.a + 1})
由于是异步执行,当执行到第二个 setState 时,this.state 的状态还未改变,因此设置的值仍为 2 。问题出在获取 state 的方式,如果为函数形式,那么 state 就能被正确的获取(因为 state 会被当做参数传入,每次传入的都是最新的 state)。
this.setState(prevState => ({a: prevState.a + 1}))
this.setState(prevState => ({a: prevState.a + 1}))
state 总结 & 补充
state中存放变动的数据,不变动的放在this下即可setState会触发梗元素重新生成虚拟树- 重新生成整颗虚拟树的结构就是所有的组件都重新被调用了
 setState是类继承过来的方法,不应该被覆盖
生命周期
生命周期函数的意义:组件获取虚拟树过程中会执行的一系列方法。

函数组件
函数组件在 v16 版本之前确实没什么好记的,只需要记住组件的传入参数是组件的 props 即可。
在 v16 版本之后出现了 hooks 记录一下
useState
useState 为 react 函数组件提供了保存状态的能力。使用如下
import { useState } from 'react';
function Example() {
    const [count, setCount] = useState(0);
    
    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>
                Click me
            </button>
        </div>
    );
}
函数需传入一个参数,返回一个数组,数组第一项为传入的值,数组第二项为一个函数,可以修改原始值。
该函数的目的在于让函数组件也拥有 state ,大概可以知道具体的执行过程。
- 通过数组返回的第二个函数修改原始值
 useState内部状态变化- 通知虚拟树的重新生成虚拟树
 - 将新的虚拟树与之前的虚拟树作对比(
diff算法),找出差别,生成更新程序(patch) - 执行更新程序 
html页面需要更新的地方就会发生变化 
其实和类组件的效果差不多,就是代码量变少了,但如果涉及复杂的组件,感觉还是类组件好用,类组件有个 this 。
useEffect
useEffect 让 react 函数组件拥有生命周期的钩子。使用如下
import { useState, useEffect } from 'react';
function FriendStatus(props) {
    const [isOnline, setIsOnline] = useState(null);
    
    function handleStatusChange(status) {
        setIsOnline(status.isOnline);
    }
    
    useEffect(() => {
        ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
        // 明确在这个 effect 之后如何清理它
        return function cleanup() {
            ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
        };
    });
    
    if (isOnline === null) {
        return 'Loading...';
    }
    return isOnline ? 'Online' : 'Offline';
}
useEffect 中传入的函数将会在组件初始化完成的时候调用,而调用的结果(结果是一个函数),将会在组件销毁的时候调用。
useRef
useRef 让 react 函数组件能使用 ref 。
function TextInputWithFocusButton() {
    const inputEl = useRef(null);
    const onButtonClick = () => {
        inputEl.current.focus();
    };
    return (
        <>
          <input ref={inputEl} type="text" />
          <button onClick={onButtonClick}>Focus the input</button>
        </>
    );
}
用法和 React.createRef() 一样,感觉这个 api 可以直接用于函数组件,哪天试一下。
useContext
useContext 需要搭配 React.createContext 使用,用于直接获取 Context 。
和组件的概念不一样,组件内部一般是不主动去获取 Context 而是通过 Provider 和 Consumer 来获取后,通过 props 传入组件内部,useContext 直接获取到最近的 Provider 处,拿到提供的值,如果没有 Provider 则取默认值,也就是传入 React.createContext 这个方法的值。
useReducer
useReducer 提供一个类似 redux 的 api ,需要一个 reducer 。
import React, { useReducer } from "react";
function reducer(state, action) {
    switch (action.type) {
        case "increment":
            return { count: state.count + 1 };
        case "decrement":
            return { count: state.count - 1 };
        default:
            return state;
    }
}
const Com = props => {
    const [state, dispatch] = useReducer(reducer, { count: 0 });
    return (
        <div value={{ state, dispatch }}>
            <botton onClick={()=>dispatch({type: 'increment'})}>+</botton>
            <botton onClick={()=>dispatch({type: 'decrement'})}>-</botton>
            {state.count}
        </div>
    );
};
当然 dispatch 也可通过 props 向子元素传递。
其他 hooks
一些目的性不强,个人感觉为了 hook 而 hook 的就不写了,总之如果逻辑简单,而函数组件满足不了时,使用这些 hook ,但逻辑复杂还是使用类组件比较好。