react 常用 hook

Hook是什么

Hook 是一个特殊的函数,它可以让你“钩入” React 的特性。例如,useState 是允许你在 React 函数组件中添加 state 的 Hook。

什么时候使用Hook

编写函数组件并需要向其添加一些 state

常用hook

useState

语法

const [count,setCount]=useState(0)

解释

通过useState()声明,会返回一个有两个元素的数组,即当前的状态更新函数。useState的参数是初始化参数。在必要时,可使用其对应更新函数设置count的值。

对比class
传统class写法

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0//初值设为0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}
import React, { useState } from 'react';

function Example() {
  // 声明一个叫 "count" 的 state 变量
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

异同

  • count值展示:class中 {this.state.count};hook中:{count}
  • count值更新:class中 this.setState({ count: this.state.count + 1 };hook中:setCount(count + 1)

注意一点:Hook 在 class 内部是不起作用的

补充

  • const [count, setCount] = useState(0)相当于 es6 中的数组解构,所以这句代码等同如下代码
const _useState = useState(0)
const count  = _useState[0]
const setCount = _useState[1]
  • 根据useState出现的顺序来保证这useState找到它自己对应的state,故useState不能存在于条件语句中

useEffect

Effect Hook 可以让你在函数组件中执行副作用操作,即在dom更新后还有其他额外操作。

这个例子,是我们通过data的初始值进行创建列表,但是当这个列表内容需要从网络请求获取时,我们就得使用到useEffect,来隔离副作用

import React, { useState } from 'react';

export default function App(){
  const [data, setData] = useState({ hits: [{id:1,typename:'a'},{id:2,typename:'b'}] });
 
  return (
    <ul>
      {data.hits.map(item => (
        <li key={item.id}>
          {item.typename}
        </li>
      ))}
    </ul>
  );
}

添加网络请求

import React, { useState } from 'react';

import axios from 'axios';

export default function App(){
  const [data, setData] = useState({ hits: [{id:1,typename:'a'},{id:2,typename:'b'}] });
 
 useEffect(async () => {
    const fetchData = async () => {
      const result = await axios(
        'http://localhost/api/v1/search?query=redux',
      );
 
      setData(result.data);
    };
 
    fetchData();
  });
  
  return (
    <ul>
      {data.hits.map(item => (
        <li key={item.id}>
          {item.typename}
        </li>
      ))}
    </ul>
  );
}

在useEffect中,不仅会请求后端的数据,还会通过调用setData来更新本地的状态,这样会触发view的更新。但是在运行这个程序时会触发无限循环。

原因:useEffect在组件mount时执行,也会在组件更新时执行。因为我们在每次请求数据之后都会设置本地的状态,所以组件会更新,因此useEffect会再次执行,因此出现了无限循环的情况。

解决: 我们只想在组件mount时请求数据。我们可以传递一个空数组作为useEffect的第二个参数,这样就能避免在组件更新执行useEffect,只会在组件mount时执行。

修改如下,只会在组件mount时执行一次

import React, { useState } from 'react';

import axios from 'axios';

export default function App(){
  const [data, setData] = useState({ hits: [{id:1,typename:'a'},{id:2,typename:'b'}] });
 
 useEffect(async () => {
    const fetchData = async () => {
      const result = await axios(
        'http://localhost/api/v1/search?query=redux',
      );
 
      setData(result.data);
    };
 
    fetchData();
  },[]);
  
  return (
    <ul>
      {data.hits.map(item => (
        <li key={item.id}>
          {item.typename}
        </li>
      ))}
    </ul>
  );
}

然而在实际开发中,我们请求可能会依赖于某个变量,这时useEffect第二个参数便可填写上这个变量。mount时执行,并且如果变量发生变化,useEffect会再次运行。

useEffect怎么实现 componentWillUnmount

在组件卸载时,我们常常要做一些操作。例如,清除定时器,避免内存泄漏;或是登录状态的取消。

useEffect 提供了 return 方法以供我们在组件卸载时清空副作用,举例如下

useEffect(()=>{
        console.log(`You clicked ${count} times`)

        return ()=>{
            console.log('组件销毁')
        }
},[])

第二个参数为空,则相当于只执行一次。若不加,则会在每次渲染时都执行。

useContext 父子组件传值

用类声明组件时,父子组件的传值是通过组件属性和props进行的。用了方法来声明组件,就没有了constructor,当然也就没有了propsuseContextredux的作用是不同的,一个解决的是组件之间值传递的问题,一个是应用中统一管理状态的问题,但通过和useReducer的配合使用,可以实现类似 Redux 的作用。

Context的作用就是对它所包含的组件树提供全局共享数据的一种技术。
步骤为:

  • createContext 函数创建context
  • useContext 接收上下文变量
    父组件
import React, { useState , createContext } from 'react'
import Son from './Son'
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}>
                <Son />
            </CountContext.Provider>

        </div>
    )
}
export default Father

子组件

import React, { useContext } from 'react'

function Son(){
    const count = useContext(CountContext)
    return (<h2>{count}</h2>)
}
export default Son

useReducer 基础应用

Reducer?形如下面这段代码就可被称为reducer

function countReducer(state, action) {
    switch(action.type) {
        case 'add':
            return state + 1;
        case 'dec':
            return state - 1;
        default: 
            return state;
    }
}

useReducer 使用 demo, 计数器加减

function ReducerDemo(){
    const [ count , dispatch ] =useReducer((state,action)=>{
        switch(action){
            case 'add':
                return state+1
            case 'dec':
                return state-1
            default:
                return state
        }
    },0)
    return (
       <div>
           <h2>分数{count}</h2>
           <button onClick={()=>dispatch('add')}>Increase</button>
           <button onClick={()=>dispatch('dec')}>Decrease</button>
       </div>
    )

}

问题及解决

在实际开发中,我们常常会遇到,可能组建中发送了一个请求,然而请求还未返回就卸载了组件,这时候,还设置这个状态,是会报错的
错误如下
在这里插入图片描述
解决方法:在这里只给出了部分代码

useEffect(() => {
    let didCancle = false
    setLoading(true)
    getWiki({ page, status: 4, isAdmin: false }).then(
      ({ dataList, msg, pageInfo }) => {
        let list: IArticle[]
        if (data && data.dataList) {
          list = [...data.dataList, ...dataList]
        } else {
          list = dataList
        }
        if (!didCancle) {
          setData({ dataList: list, pageInfo, msg })
          setLoading(false)
        }
      },
      err => {
        setLoading(false)
        toast(err)
      }
    )
    return () => {
      didCancle = true
    }
  }, [page])

新增 didCancle 变量,如果变量为true则不再去设置组件渲染所以依赖的数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值