React Hooks

85 阅读4分钟

class组件与函数hooks组件的写法

//class写法
import React, {Component} from 'react'
class Test extends Component(){
  constructor(props){
    super(props)
    this.state = { count:0 }
  }
  render(){
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick = {this.addCount.bind(this)}>Click me</button>
      </div>
    )  
  }
  addClick(){
    this.setState({count:this.state.count + 1})
  }
}
export default Test


//hooks写法
import React, {useState} from 'react'
function Test(){
  const [count, setCount] = useState(0)
    return (
      <div>
        <p>You clicked {count} times</p>
        <button onClick = {()=>{setCount(count+1)}}>Click me</button>
      </div>
    )  
}
export default Test

Hooks API

useState

const [count, setCount] = useState(0)  //简单声明,其中useState参数为count初始值,setCount为改变数据函数
//不用结构赋值
let _useState = useState(0)
let count = _useState[0]
let setCount = _useState[1]

useEffect

import React, {useEffect} from 'react'
function Test(){
  useEffect(()=>{
    console.log(1111) //相当于componentDidMount与componentDidUpdate的结合,用于处理副作用与替代生命周期函数
  })
}

实现componentWiiUnmount,在组件销毁前取消绑定

useEffect(()=>{
  return ()=>{       //useEffect可以返回一个函数,在组件更新/销毁时执行
    console.log("逻辑执行")
  }
}, [])     //数组为空的时候意味只有组件销毁的时候执行return的函数,有值则代表那个值变化时执行

useContext

用于解决父子组件传值的问题,其可访问全局

import React, { useState, createContext, useContext } from 'react'
const CountContext = createContext()  //创建一个上下文对象
//父组件
function Father(){
  const [count, setCount] = useState(0)
    return (
      <div>
        <p>You clicked {count} times</p>
        <button onClick = {()=>{setCount(count+1)}}>Click me</button>
        <CountContext.Provider value={count}>   //value为共享出去的数据
          <Child />//需要传值的子组件
        </CountContext>
      </div>
    )
}


//子组件
function Child(){
  let count = useContext(CountContext)
  return (<h2>{count}</h2>)     //此处的count为接收到的参数
}

useReducer

//js版本的Reducer
function countReducer(state, action){   //state为传入的需要改变的参数,action为具体的操作
  switch(action.type){
    case 'add':
      return state + 1
    case 'sub':
      return state - 1
    default:
      return state
  }
}


//使用useReducer
import React, { useReducer } from 'react'
function ReducerDeemo(){
  const [count, dispatch] = useReducer((state, action)=>{   //使用useReducer包裹
    switch(action){
      case 'add':
        return state + 1
      case 'sub':
        return state - 1
      default:
        return state
    }
  }, 0)


  return(
    <div>
      <h2>count:{count}</h2>
      <button onclick={()=>{dispatch('add')}}></button>   //通过dispath传入的参数实现不同操作
      <button onclick={()=>{dispatch('sub')}}></button>
    </div>
  )
}

useReducer与useContext实现Redux效果

boundary-start ---UI---

//UI部分
import React, { useContext } from 'react'
import { Color, ColorContext, UPDATE_COLOR } from 'color.js' //由于没有使用默认样式,Color组件必须使用 {} 进行引入


//字体展示部分
function TextArea(){
  const {color} = useContext(ColorContex)
  return(
    <div style={{color:color}}>字体显示</div>
  )
}


//按钮部分
function Button (){
  const {dispatch} = useContext(ColorContext)
  return (
    <div>
      <Color>     //使用context组件包裹,实现color的共享
        <button onClick={()=>{dispatch({type:UPDATE_COLOR,color:'red'})}}>红色</button>
        <button onClick={()=>{dispatch({type:UPDATE_COLOR,color:'yellow'})}}>黄色</button>
      </Color>
    </div>
  )
}


//主体结构
function Main(){
  return(
    <div>
      <TextArea />
      <Button />
    </div>
  )
}

boundary-end ------

boundary-start ---创建context---

//创建context
import React, { createContext, useReducer } from 'react'
export const ColorContext = createContext({})  //生成一个context对象
export const UPDATE_COLOR = "UPDATE_COLOR"   //建立操作常量,不容易出错
const reducer = (state, action) => {
  switch(action.type){
    case UPDATE_COLOR:
      return action.color
    default:
      return state
  }
}
export const Color = props=>{
  const [color, dispatch] = useReducer(reducer, 'blue')     //dispatch为派发器负责处理响应
  return (
    <ColorContext value={{color,dispatch}}>
      {props.children}
    </ColorContext>
  ) 
}

boundary-end ------

_useMemo

boundary-end ------

其通过按条件阻止组件渲染解决Hooks的性能问题,主要替代shouldComponentUpdate

父组件发生任意变化都会影响子组件导致子组件更新并重新渲染,因此会产生严重的性能问题

import React, { useMemo } from 'react'
const test = useMemo(()=>fun(),[]) //参数一为限制执行的函数,参数二为监控的状态,只有被监控的状态改变时函数才执行

_useRef

其用于获取jsx中的DOM或是保存变量

函数组件与类组件区别

函数组件会捕获渲染帧的数据,类组件由于this指向问题导致获取的是最新渲染帧的数据(props)

尽管优化策略有些许不同,但性能的差异几乎可以忽略不计

经典例子:延迟三秒打印props中的数据

//函数组件
function ProfilePage(props) {      //原先hooks没有推出时函数组件又被称为无状态组件,此处的参数为外部传入
  const showMessage = () => {
    alert('Followed ' + props.user);
  };


  const handleClick = () => {
    setTimeout(showMessage, 3000);   //延迟三秒打印数据
  };


  return (
    <button onClick={handleClick}>Follow</button>
  );
}
//函数组件在点击按钮并切换数据后依旧打印切换前的数据


//类组件
class ProfilePage extends React.Component {
  showMessage = () => {
    alert('Followed ' + this.props.user); 
  };


  handleClick = () => {
    setTimeout(this.showMessage, 3000); //注意此处的this指向,回调函数执行时其this指向的是三秒后的props
  };


  render() {
    return <button onClick={this.handleClick}>Follow</button>;
  }
}
//类组件在点击按钮并切换数据后打印切换后的数据,这种情况相当于获取到了"未来"的数据

类组件可以通过闭包解决这个问题

class ProfilePage extends React.Component {
  render() {
    // 通过在render中绑定props捕获当前帧数据
    const props = this.props;


    const showMessage = () => {
      alert('Followed ' + props.user);   //此时的数据为被绑定的数据
    };


    const handleClick = () => {
      setTimeout(showMessage, 3000);
    };


    return <button onClick={handleClick}>Follow</button>;
  }
}

函数式组件也可以通过ref来达到获取"未来数据的效果"

function MessageThread() {
  const [message, setMessage] = useState('');


  // Keep track of the latest value.
  const latestMessage = useRef('');
  useEffect(() => {
    latestMessage.current = message;  //获取到最新渲染帧的数据
  });


  const showMessage = () => {
    alert('You said: ' + latestMessage.current);
};