react中hooks、diff等知识点总结

一、基础hook

1、useState

// defaultValue 默认值
// 使用数组方便命名结构
const [value,setValue] = useState(defaultValue);
// 初始化执行后 value的值 只能通过setValue改变 通过传递props是无法改变的
// value如果是父组件传递进来的化 只在初次渲染会复制 后续触发的更新不能修改value值
// 也就是说value值只能通过setValue修改 父组件改变props.value触发的更新不会更新value值
const [value,setValue] = useState(props.value);

2、useEffect

// 完成副作用操作 类似类组件的生命周期钩子 用于改变DOM,添加订阅,定时器等等操作
// 该函数会在组件渲染到页面后执行
// 接收一个函数和一个数组作为参数(函数可返回一个函数,用于清除计时器、等于等)
// 数组是条件执行依赖,当依赖变更后会重新执行
useEffect(()=>{}, [])

3、useContext

// 主要用于数据共享,共享数据不需要通过父组件层层传递给子组件
// 接收一个React.createContext创建的值
// 该对象有俩个属性Provider Consumer 生产者 消费者
const UserInfoContext = React.createContext({});
// userlist组件 均可以获取到value传递的值 不用特意去给这些组件传递props
const UserList0 = ()=> {
    const { username } = useContext(UserInfoContext)
    return <span>{username}</span>
}
const UserList1 = ()=> {
    const { username } = useContext(UserInfoContext)
    return <span>{username}</span>
}
const UserList2= ()=> {
    const { username } = useContext(UserInfoContext)
    return <span>{username}</span>
}

<UserInfoContext.Provider value={{username: 'admin'}}>
                <UserList0 />
                <UserList1 />
                <UserList2 />
            </UserInfoContext.Provider>

二、额外hook

1、useReducer

// useState 的替代方案
// 使用方式和redux类型
// 接收参数会reducer、state、init
// init: 函数类型 惰性初始化 可以将state的处理放在reducer 外部,方便重置state和action
const state = 'name';
const init = (state )=> {
    return {
        name: state 
    }
}
const reducer = (state, action)=> {
    switch(action.type) {
        ...
    }
}
const [value, dispatch] = useReducer(reducer, state, init);

2、useCallback

// 参数是一个函数和一个数组依赖
// 只有等依赖变更时才会执行,返回值是一个函数,如果依赖未改变返回的是缓存的函数
// 主要用于父组件传递给子组件函数类型时 避免子组件做不必要的渲染
// InputNum 在父组件num更新时,不再更新
const InputNum = memo((props: any) => {
    const {onChange} = props;
    console.log(5)
    return <input type="text" onChange={onChange}/>
})

const App = ()=> {
     const [num, setNum] = useState(0);
    const [text, setText] = useState('0');

    const onChange = useCallback((e: any)=> {
        setText(e.target.value);
    }, []);

    return (
        <BasicContents>
            <span>num:{num}</span><br/>
            <span>text:{text}</span><br/>
            <InputNum onChange={onChange}/><br/>
            <button onClick={() => {
                setNum(num + 1)
            }}>更新
            </button>
        </BasicContents>
    )
}

3、useMemo

// 接收一个函数 和一个数组依赖做完参数 和useEffect一样
// 主要用于性能优化的 因为函数组件没有shouldComponentUpdate和PureComponent
// 在父组件更新时 必然会更新子组件 如果子组件有一些较大的开销(循环等) 容易有性能问题
// useMemo 仅在依赖变更时 才会执行函数,从新计算, 否则返回缓存的值

const Sum = (props:any)=> {
     const num = props.num;
     const sum = useMemo(()=> {
     let _sum = 0;
     for(let i = 0; i< num; i ++) {
        _sum ++;
     }
     return _sum 
    }, [num]);

    return <span>{sum}</span>
}


const App = ()=> {
    const [num, setNum] = useState(10);
    return (
        <Sum num={num} />
    )
}

4、useImperativeHandle

// 主要是子组件暴露ref的实例给父组件 一般配合forwardRef使用
// forwardRef  使父组件可以拿到子组件的实例
const FancyButton = React.forwardRef((props: any, ref: any) => (
    <Button ref={ref} type="primary" htmlType="submit">
        {props.children}
    </Button>
));
// bthRef 可以拿到Button的实例
<FancyButton ref={bthRef} onClick={onOk}>确定</FancyButton>;
// useImperativeHandle 自定义暴露给父组件的实例属性(click)
const FancyButton = React.forwardRef((props: any, ref: any) => {
   useImperativeHandle(ref, () => ({
    click: () => {
      ref.current.click();
    }
  }));
    return <Button ref={ref} type="primary" htmlType="submit">
        {props.children}
        </Button>
});

5、useLayoutEffect

// 作用类似useEffect 但是执行的时机不同,它是在dom变更之前,渲染的时候同步执行的
// 一般是避免视觉上不一致才会用到
useLayoutEffect(()=>{}, [])

6、useDebugValue

// 用于在 React 开发者工具中显示自定义 hook 的标签。

7、自定义hook

// 命名规范以use开头
// 属于功能抽象 跟高阶组件作用一样
// 例子:定义一个获取鼠标点击的hook

const useKeyDown = () => {
    const [key, setKey] = useState(null);
    useEffect(() => {
        const _keydown = (e: any) => {
            setKey(e.code);
        };
        document.addEventListener('keydown', _keydown);
        return () => {
            document.removeEventListener('keydown', _keydown)
        }
    }, []);
    return key
}

// 使用方式
const App = ()=> {
    const key = useKeyDown();
    return (
        <div>{key}</div>
    )
}

二、类组件生命周期

  1. 挂载(mount)

    componentWillMount          组件即将挂载

    componentDidMount          组件挂载完成

    componentWillUnmount     组件销毁

  2. 更新(upData)

    componentWillReceiveProps  props改变

    shouldComponentUpdate       是否更改state

    componentWillUpdate            状态即将更新

    render                                     渲染

     componentDidUpdate           更新完成

四、函数组件和类组件的区别

函数组件没有状态,只能访问props参数,无副作用

组件不会被实例化,会提高渲染性能

没有生命周期,不能访问this

五、虚拟dom、diff、fiber、key等知识点 

  1. 虚拟dom

    模拟真实dom的一个js对象树。是为了同一计算所有的变换后,一个更新dom。尽量减少对dom的操作。

  2. diff

    将虚拟dom转换成真实dom树的最少操作的实现就是diff算法。

    tree diff:不跨层级进行移动操作,只对同一节点下的子节点进行比较。

    component diff:拥有相同类的俩个组件生成相似的树形结构,拥有不同类的俩个组件生成不同的树形结构。

    element diff:对于同一层级的节点,通过唯一id区分(key)

  3. fiber

    解决组件渲染过程中的同步阻塞问题而做的任务分割,主要是通过单链表树遍历算法,可以记录遍历当下的上一步和下一步,使遍历可以暂停。

    使用requestIdleCallback函数,在浏览器渲染空闲时机进行diff。

  4. key

减少不必要的diff算法对比,主要在diff对比前做一个校验,通过key来判断组件是否存在,是需要更新、销毁、新建等操作,提供diff算法的性能。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值