React Hook复习

前几日速成了一下react全家桶,在实战过程中,有点懵逼,来总结一下。

State

import React, { useState } from 'react';

function Example(){
	const [ count, setCount ] = useState(0);
    
    return(
    	<div onClick={()=>setCount(count + 1)}>Click Me!</div>
    )
}
  • useState会返回一对值:当前状态和一个让你更新的它的函数;
  • setXXX 不会把新的state和旧的state进行合并,例如:state可以是一个对象,在更新对象类型时,切记要合并旧的状态,否则旧的状态会丢失;
import React, { useState } from 'react';

function Example(){
	const [ params, setParams ] = useState({
        rotate: 0,
        color: '#000'
    });
    
    const handleInputChange = event =>{
        const traget = event.target;
        setParams({
            ...params,
            [target.name]:target.value
        })
    }
    
    return()
}


// 声明多个 state 变量!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

Effect

useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMountcomponentDidUpdatecomponentWillUnmount 具有相同的用途,只不过被合并成了一个 API。

import React, { useState, useEffect } from 'react';

function Example(){
	const [ count, setCount ] = useState(0);
    
    // 相当于 componentDidMount 和 componentDidUpdate.
    // 默认情况下,React 会在每次渲染后调用副作用函数 —— 包括第一次渲染的时候。
    useEffect(()=>{
        document.title = `You Clicked ${count} times`;
    })
    
    return(
    	<div onClick={()=>setCount(count + 1)}>Click Me!</div>
    )
}

useEffect还可以在页面销毁时执行

useEffect(()=>{
    // 相当于 componentDidMount 和 componentDidUpdate.
	document.title = `You Clicked ${count} times`;
    // 相当于 componentWillUnmount.
    return ()=>{
        console.log("我被销毁啦~");
    }
})

useEffect的第二个参数,当count发生改变时,才会执行useEffect里面的函数

useEffect(()=>{
    // 相当于 componentDidMount 和 componentDidUpdate.
	document.title = `You Clicked ${count} times`;
    // 相当于 componentWillUnmount.
    return ()=>{
        console.log("我被销毁啦~");
    }
},[count])

useState 一样,你可以在组件中多次使用 useEffect

Context

这个hook应该是为了弥补props

import React, { useState, createContext, useContext } from 'react';
const CountContext = createContext();

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

  return(
    <div>
      <p>click: {count}</p>
      <button onClick={()=>setCount(count+1)}>Clcik Me</button>
      <CountContext.Provider value={count}>
        <Counter/>
      </CountContext.Provider>
    </div>
  )
}

function Counter(){
  const count = useContext(CountContext);
  return(
    <h2>{count}</h2>
  )
}

export default Test;
}

当不同文件的组件公用一个变量时,应该提取。

Reducer

之前有个例子是使用useState写的计数器,每点击一次按钮,就加一

import React, { useState } from 'react';

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

  return(
    <div>
      <p>click: {count}</p>
      <button onClick={()=>setCount(count+1)}>Clcik Me</button>
    </div>
  )
}

export default Test;

如果场景是加减呢,使用useState就行不通,所以可以使用useReducer

import React, { useReducer } from 'react';
const initialState = { count : 0 };
function reducer(state, action){
  switch(action.type){
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Test (){
  const [ state, dispatch ] = useReducer(reducer, initialState);

  return(
    <div>
      <p>click: {state.count}</p>
      <button onClick={()=>dispatch({type:'decrement'})}>decrement</button>
      <button onClick={()=>dispatch({type:'increment'})}>increment</button>
    </div>
  )
}

export default Test;

Memo

useMemo主要用来解决使用React hooks产生的无用渲染的性能问题。使用function的形式来声明组件,失去了shouldCompnentUpdate(在组件更新之前)这个生命周期,也就是说我们没有办法通过组件更新前条件来决定组件是否更新。而且在函数组件中,也不再区分mountupdate两个状态,这意味着函数组件的每一次调用都会执行内部的所有逻辑,就带来了非常大的性能损耗。

父组件中有ab两个变量,两个AB按钮和一个子组件,点击A按钮改变a的值,点击B按钮改变b的值,子组件的内容会根据a的改变而改变。

import React, { useState } from 'react';

function Test (){
  const [a, setA] = useState('我是A');
  const [b, setB] = useState('我是B');

  return(
    <div>
      <button onClick={()=>{setA('点击了A')}}>A</button>
      <button onClick={()=>{setA('点击了B')}}>B</button>
      <ChildComponent name={a}>我只子组件</ChildComponent>
    </div>
  )
}

function ChildComponent({name}){
  function changeA(name){
    console.log(`ChildComponent change ${name}`);
    return `ChildComponent change ${name}`;
  }

  const actionA = changeA(name);
  return (
    <div>
      <div>{actionA}</div>
    </div>
  )
}

export default Test;

虽然我们想要的是,当点击了A按钮,a的值发生了改变,然后子组件打印出ChildComponent change 点击了A,但是发现点击B按钮也会打印,这不是我们希望的,可以使用useMemo优化性能。

把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。

// 记得引入useMemo
const actionA = useMemo(()=>changeA(name),[name]);

我们可以用于导出的时候:

export default React.memo(Test)

补充PureComponentComponent

class App extends PureComponent{}
class App extends Component{}
  • Component只要setState()和props的改变就会触发render
    而我们不想页面重新render就得自己写shouldComponentUpdate来拦截render.

    shouldComponentUpdate(nextProps, nextState) {
      return nextProps.xxx.xx === props.xxx.xx;
    }
    
  • PureComponent为你处理shouldComponentUpdate事件
    当props或state发生变化,PureComponent会对两者都做浅比较;浅比较只会检查基本数据类型的值是否相等(比如:1等于1或者true等于true),复杂如对象和数组只是比较引用值
    并且只会去比较第一层的。

class App extends PureComponent {
  state = {
    items: [1, 2, 3]
  }
  handleClick = () => {
    const { items } = this.state;
    items.pop();
    this.setState({ items });
  }
  render() {
    return (<div>
      <ul>
        {this.state.items.map(i => <li key={i}>{i}</li>)}
      </ul>
      <button onClick={this.handleClick}>delete</button>
    </div>)
  }
}

会发现,无论怎么点 delete 按钮, li 都不会变少,因为 items 用的是一个引用。

handleClick = () => {
  const { items } = this.state;
  items.pop();
  this.setState({ items: [].concat(items) });
}

useRef

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。

const refContainer = useRef(initialValue);
function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` 指向已挂载到 DOM 上的文本输入元素
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值