美文网首页
react hook小记

react hook小记

作者: 三粒黑子球 | 来源:发表于2021-05-24 11:23 被阅读0次

useState

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

useState 返回的第一个值将始终是更新后最新的 state,并且与 class 组件中的 setState 方法不同,useState 不会自己合并更新对象。但是可以通过用函数式的 setState 结合展开运算符来达到合并更新对象的效果。效果如下

setState(prevState => {
  //  Object.assign 也可以实现这种效果 
  return {...prevState, ...updatedValues};
});

useEffect

  • 1
    useEffect 用来完成副作用操作。赋值给 useEffect 的函数会在组件渲染到屏幕之后执行(延迟执行)
  • 2
    useEffect 传递的第二个参数,用来控制useEffect的执行时机,是一个数组。传入空数组 表示只更新一次相当与classcomponentDidMount 只会执行一次。
  • 3
    受同一种数值影响影响的放在同一块 例如
function Example({ someProp }) {
  useEffect(() => {
    function doSomething() {
      console.log(someProp);
    }

    doSomething();
  }, [someProp]); 
}

或者订阅和消除 放在一起

useEffect(() => {
  const subscription = props.source.subscribe();
  return () => {
    // 清除订阅
    subscription.unsubscribe();
  };
});

这样可以控制重复订阅以及 解决没有必要调用 。

  • 3
    componentDidMountcomponentDidUpdate 不同,useEffect 的函数会在完成布局与绘制后,被延迟调用。(所以这使得他适用于很多常见你的副作用场景)。然而,并非所有 effect 都需要被延迟执行。例如,一个对用户可见的 DOM 变更就必须在浏览器执行下一次绘制前被同步执行,这样用户才不会感觉到视觉上的不一致。(概念上类似于被动监听事件和主动监听事件的区别。)React 为此提供了一个额外的 useLayoutEffectHook 来处理这类 effect。它和 useEffect 的结构相同,区别只是调用时机不同。
    虽然 useEffect 会在浏览器绘制后延迟执行,但会保证在任何新的渲染前执行。在开始新的更新前,React 总会先清除上一轮渲染的 effect。例子可以参考这里

useContext

这个可以获取共享的value的值

const value = useContext(MyContext);

举一个例子 如下

// test-context.js
import React from 'react';
export const TestContext = React.createContext('我是传过去的值');
//LoginScreen.js
import React, {useState,useEffect,useLayoutEffect} from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import BigView from '../Component/BigView';
import {TestContext,themes} from '../Utils/test-context.js';

const LoginScreen = (props) => {
    const [value, setValue] = useState("sdssdsdssdd");
    const onClick = () => {
         setValue((prevState) => {
             if (prevState == '我是传过去的值') {
                 return '我改变了';
            }
             return '我是传过去的值';
         });
    }
    return (
        <View style = {{flex:1}}>
            <TestContext.Provider value={value}>
                <BigView/>
            </TestContext.Provider>
        </View>
    );
}

export default LoginScreen;
//BigView.js
import React, {useEffect} from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import MiddleView from '../Component/MiddleView';

const BigView =  (props) => {
    useEffect(()=>{
        console.log('BigView useEffect begin ');
    });
    return (
        <View style = {{height:200,backgroundColor:'red'}}>
            <MiddleView/>
        </View>
    );
}

export default React.memo(BigView);
import React, { useEffect,useContext} from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import {TestContext,themes} from '../Utils/test-context.js';

const MiddleView = (props) => {
    useEffect(()=>{
        console.log('MiddleView useEffect begin ');
    });
    let value = useContext(TestContext);
    console.log('value ==============',value);// 这里可以获取改变的value 的数值
    return (
        <TestContext.Consumer>
            {(theme) => {
                return (
                    <View style = {{height:100,backgroundColor:'green'}}>
                        <Text>{theme}</Text>
                    </View>
                );
            }}
        </TestContext.Consumer>
    );
}

export default MiddleView;

在上面的例子当我改变的时候 只有 MiddleViewLoginScreen发生了改变,如果没有 使用 React.createContext那么修改 LoginScreen 只会改变
LoginScreenBigView 不会重新渲染。这个以后会出一个文章比对说明一下。

useEffect

  • 1
    createRef 和 useRef 的作用可以说完全一样,但是 useRef hook为DOM节点创建持久引用 ,相当于this 不会发上改变。也就是说 createRef 每次渲染都会返回一个新的引用,而 useRef 每次都会返回相同的引用。举一个例子
import React, {useEffect,useState,useRef,createRef} from 'react';
import { View, Text,Button } from 'react-native';

const BigView =  (props) => {
    const [ index,setIndex ] = useState(0)
    const iAmUseRef = useRef();
    const iAmCreateRef = createRef();

    if (!iAmUseRef.current) {
        iAmUseRef.current = index;
    }
    if (!iAmCreateRef.current) {
        iAmCreateRef.current = index;
    }
    return (
        <View style = {{height:200,backgroundColor:'red'}}>
            
            <Button title = {'add index'} onPress = {() => setIndex(index + 1)}/>
            <Text>{'current index is ', index}</Text>
            <Text>{'useRef.current is ', iAmUseRef.current}</Text>
            <Text>{'createRef.current is', iAmCreateRef.current}</Text>
        </View>
    );
}

export default React.memo(BigView);
效果图

很明显 可以看出 useRef 并未发生改变 ,createRef 每次重新render会重新生成新的引用 会随着数字的变化而变化 。
useRef 相当于this createRef 会随着变化而变化。

useReducer

  • 1 有一些类似 Redux 。
  • 2 useReducer可以使代码具有更好的可读性、可维护性、可预测性。
  • 3 子组件中直接通过context拿到dispatch,触发reducer操作state 子组件。对组件层级很深的场景特别有用,不需要一层一层的把 state 和 callback 往下传
  • 4 惰性初始化
function init(initialCount) {
  return {count: initialCount};
}

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    case 'reset':
      return init(action.payload);
    default:
      throw new Error();
  }
}

function Counter({initialCount}) {
  const [state, dispatch] = useReducer(reducer, initialCount, init);
  return (
    <>
      Count: {state.count}
      <button
        onClick={() => dispatch({type: 'reset', payload: initialCount})}>
        Reset
      </button>
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

useCallback 和 useMemo 和 memo

    1. useMemo 计算结果是 return 回来的值, 主要用于 缓存计算结果的值 ,应用场景如: 需要 计算的状态 useMemo 可以用来 细粒度性能优化 。意思也就是说 如果你只希望 组件的 的部分不要进行重新渲染,而不是整个 组件 不要 重新渲染,实现 局部 Pure 功能。那么可以按照下面这么用。
import React, { useMemo } from 'react';

export default (props = {}) => {
    console.log(`--- component re-render ---`);
    return useMemo(() => {
        console.log(`--- useMemo re-render ---`);
        return <div>
            <p>number is : {props.number}</p>
        </div>
    }, [props.number]);
}
    1. useCallback 计算结果是 函数, 主要用于 缓存函数,应用场景如: 需要缓存的函数,因为函数式组件每次任何一个 state 的变化 整个组件 都会被重新刷新,一些函数是没有必要被重新刷新的,此时就应该缓存起来,提高性能,和减少资源浪费。
    1. React.memo 与 PureComponent 很相似,但是是专门给 Function Component 提供的,可以支持指定一个参数,可以相当于 shouldComponentUpdate 的作用。有点类似 HOC(高阶组件),在并且内部实现 PureComponent + shouldComponentUpdate 的结合使用。按照下面的例子来说 isEqual是用来判断两次 props 是否有,第二个参数不传递,默认只会进行 props 的浅比较。 与 class 组件中 shouldComponentUpdate() 方法不同的是,如果 props 相等,areEqual会返回 true;如果 props 不相等,则返回 false。这与 shouldComponentUpdate 方法的返回值相反。
function SomeComponent(props) {
  /* 组件渲染*/
}
function isEqual(prevProps, nextProps) {
  /*
  这个方法用来比较前后两次的 Props 是否发生变化 需要自己配置 
  */
}
export default React.memo(SomeComponent, isEqual);
    1. 区别是 useMemo 将调用 fn 函数并返回其结果,而useCallback 将返回 fn 函数而不调用它。React.memo主要针对组件进行 PureComponent优化。
    1. 下面我举个例子
      Class Component中考虑以下的场景:
class BaseComponent extends Component {
  handleClick() {
    console.log('Click happened');
  }
  render() {
    return <Button onPress={() => this.handleClick()}>Click Me</Button>;
  }
}

传给 Button 的 onPress 方法每次都是重新创建的,这会导致每次 Foo render 的时候,Button 也跟着 render。优化方法有 2 种,箭头函数bind

同样的,Function Component也有这个问题:

function BaseComponent() {
  const [count, setCount] = useState(0);

  const handleClick() {
    console.log(` click happened ${count}`)
  }
  return <Button onClick={handleClick}>Click Me</Button>;
}

React 给出的方案是useCallback。在依赖不变的情况下 (在我们的例子中是 count ),它会返回相同的引用,避免子组件进行无意义的重复渲染:

function BaseComponent() {
  const [count, setCount] = useState(0);

  const memoizedHandleClick = useCallback(
    () => console.log(`Click happened ${count}`), [count],
  ); 
  return <Button onClick={memoizedHandleClick}>Click Me</Button>;
}

useMemo缓存的则是方法的返回值。使用场景是减少不必要的子组件渲染:

function BaseComponent({ a, b }) {
  // 当 a 改变时才会重新渲染
  const child1 = useMemo(() => <Child1 a={a} />, [a]);
  // 当 b 改变时才会重新渲染
  const child2 = useMemo(() => <Child2 b={b} />, [b]);
  return (
    <>
      {child1}
      {child2}
    </>
  )
}

上面的例子只有a 发生改变的时候 Child1才会改变, b发生改变的时候 Child2才会改变。

如果想实现Class Component的shouldComponentUpdate方法,可以使用React.memo方法,区别是它只能比较 props,不会比较 state:

const BaseComponent = React.memo(({ a, b }) => {
  // 当 a 改变时才会重新渲染
  const child1 = useMemo(() => <Child1 a={a} />, [a]);
  // 当 b 改变时才会重新渲染
  const child2 = useMemo(() => <Child2 b={b} />, [b]);
  return (
    <>
      {child1}
      {child2}
    </>
  )
});

useImperativeHandle 和 forwardRef

    1. useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值, useImperativeHandle 应当与 forwardRef一起使用
const SomeView = React.forwardRef(({isFollow},ref) => {
    const [follow,setFollow] = useState(!!isFollow);
    const followRef = useRef();
    useEffect(() => {
        // do something
    },[]);
//这个方法用来导出方法  外面的方法可以通过 Ref.current.function 调用
    useImperativeHandle(ref, () => ({
        setFollowState: (isFollow) => {
            if (!!followRef) {
                followRef.current.setFollowState(isFollow);
            }

        }
    }));
    return(
        <View style = {{
            width: 750,
            height: 450
            backgroundColor:'rgba(1,5,13,0.7)'}}>
            <FollowButton
                ref = {followRef}
                isFollow = {follow} />
        </View>
    );
});
const BigView =  (props) => {
    const someViewRef = useRef();
   
    const onChange = () => {
        someViewRef.current.setFollowState(false);
    }

    return (
        <View style = {{flex:1}}>
          <SomeView />
          <Button title = {'切换'} ref = {someViewRef} onPress = {onChange} />
        </View>
    );
}

export default React.memo(BigView);

从上面可以看出 useImperativeHandle 是function 组件调用模块方法的途经.
ok,先总结这么多。

相关文章

  • react hook小记

    useState useState 返回的第一个值将始终是更新后最新的 state,并且与 class 组件中的 ...

  • React hook 10种 Hook

    React hook 10种 Hook (详细介绍及使用) React Hook是什么?React官网是这么介绍的...

  • 学习react hook的总结

    react16推出了react hook,react hook使得functional组件拥有了class组件的一...

  • react-hook-form使用

    官网地址:https://react-hook-form.com/[https://react-hook-form...

  • react hook介绍

    react hook是什么 react hook是react中引入新特性,它可以让react函数组件也拥有状态;通...

  • React Hook介绍与使用心得

    关于React Hook React Hook 对于React来说无疑是一个伟大的特性,它将React从类组件推向...

  • React Hook

    Through 4 questions introduce React Hook What is Hook? In...

  • react-hook

    react-hook

  • react hook入门

    一、react hook介绍 Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情...

  • React Hooks - 学习笔记

    React Hooks Hook 是能让你在函数组件中“钩入” React 特性的函数。 State Hook u...

网友评论

      本文标题:react hook小记

      本文链接:https://www.haomeiwen.com/subject/rtledltx.html