React - Hooks 使用(函数组件中使用 React 特性)
Hook
是React 16.8.0版本增加的新特性/新语法- 可以在函数组件中使用 state 以及其他的 React 特性
- HOOK API: https://react.docschina.org/docs/hooks-intro.html
一. 为什么要使用 HOOK?
- React的组件创建方式,一种是类组件,一种是函数组件。
- 函数组件相比较类组件,具有以下特点:
(1)函数组件没有状态
(2)函数组件没有生命周期
(3)函数组件没有this
- 这就说明函数组件,只能做UI展示的功能,涉及到状态的管理与切换,就不得不用类组件或者redux。
- 在这种情况下,如果想使用函数组件编写一个完整的功能,就可以使用
HOOKS
。
二. HOOK 概念
Hook
是React 16.8.0版本增加的新特性/新语法- 可以在函数组件中使用 state 以及其他的 React 特性
三. HOOK 用法
1. useState
使函数组件也可以有
state
状态, 并进行状态数据的读写操作。
1.1 使用方法
import { useState } from "react";
const [state, setState] = useState(initState);
initState
: useState 参数
在初始渲染期间,指定state
值在内部作缓存[state, setState]
: useState 返回值,包含两个元素的数组,
第一个参数:为内部当前的state
状态值,
第二个参数:为更新state
状态值的函数
1.2 setState 两种写法
-
第一种写法
setState(newState);
参数为 非函数值,直接指定新的状态值,内部用其覆盖原来的状态值
-
第二种写法
setState(state => { // state : 原本的state值 return newState });
参数为函数,接收原本的状态值,返回新的状态值,内部用其覆盖原来的状态值
1.3 setState 实例
import React from "react";
import { useState } from "react";
export default function Demo() {
const [count, setCount] = useState(0);
function add1() {
setCount(count + 1);
}
function add2() {
// count : 原本的state值
setCount((count) => {
return count + 2;
});
}
return (
<div>
<h2>当前数值:{count}</h2>
<button onClick={add1}>+1</button>
<button onClick={add2}>+2</button>
</div>
);
}
2. useEffect
在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)
可以用来更好的处理副作用,比如 添加订阅、设置定时器、接口请求 以及执行其他包含副作用的操作
2.1 使用方法
import { useEffect } from "react";
useEffect(
() => {
// 在此可以执行任何带副作用操作
return () => { // 在组件卸载前执行
// 在此做一些收尾工作, 比如清除定时器/取消订阅等
};
},
[stateValue],// 如果指定的是[], 回调函数只会在第一次render()后执行
);
可以把 useEffect Hook 看做如下三个函数的组合:
componentDidMount()
componentDidUpdate()
componentWillUnmount()
2.2 useEffect 实例
src/index.js 暴露 root
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
export default root;
import React from "react";
import { useState, useEffect } from "react";
import root from "../../index"; //引入root路径
export default function Demo() {
const [count, setCount] = useState(0);
useEffect(() => {
// 定时器
let timer = setInterval(() => {
setCount((count) => count + 1);
}, 1000);
return () => {
// 清除定时器
clearInterval(timer);
};
}, []);
function unMount() {
root.unmount();
}
return (
<div>
<h2>当前数值:{count}</h2>
<button onClick={unMount}>卸载组件</button>
</div>
);
}
3. useRef
可以在函数组件中存储/查找组件内的标签或任意其它数据
作用:保存标签对象,功能与React.createRef()
一样
3.1 使用方法
import { useRef } from "react";
const refContainer = useRef(initValue);
3.2 useRef 实例
import React from "react";
import { useRef } from "react";
export default function Demo() {
const myRef = useRef();
function showInputValue() {
console.log(myRef.current.value);
}
return (
<div>
<input ref={myRef} type="text" />
<button onClick={showInputValue}>打印输入框信息</button>
</div>
);
}
4. useContext
接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。
4.1 使用方法
const value = useContext(MyContext);
4.2 useContext 实例
import React from "react";
import { useState, createContext, useContext } from "react";
// 创建一个createContext对象
const CountContext = createContext();
const { Provider } = CountContext;
export default function A() {
const [user] = useState({
name: "tom",
age: 18,
});
return (
<div>
<h2>A组件</h2>
<h4>姓名:{user.name}</h4>
<Provider value={user}>
<B />
</Provider>
</div>
);
}
function B() {
return (
<div>
<h2>B组件</h2>
<C />
</div>
);
}
function C() {
// 使用 useContext 接收 A组件的参数
const value = useContext(CountContext);
return (
<div>
<h2>D组件</h2>
<h4>
接收到的A组件数值为:{value.name}—{value.age}
</h4>
</div>
);
}
5. useMemo
5.1 使用方法
- 它仅会在某个依赖项改变时才重新计算 memoized 值,有助于避免在每次渲染时都进行高开销的计算。
- 简而言之,
useMemo
是用来缓存计算属性
的。
const memoizedValue = useMemo(callback, array);
- 返回一个 memoized 值。
- callback 是一个函数用于处理逻辑。
- array 控制useMemo重新执⾏的数组,array改变时才会重新执行useMemo
5.2 useMemo 实例
import React, { useState, useMemo } from "react";
export default function Page1() {
const [num, setNum] = useState(0);
// 使用 useMemo 根据 num 值计算新值
const memoNum = useMemo(() => {
return num * 2;
}, [num]);
return (
<div>
<div>当前数值:{num}</div>
<div>当前数值 * 2 后的新值:{memoNum}</div>
<button onClick={() => { setNum(num + 1) }}> +1 </button>
</div>
);
}
四. 一个 Hook 组件实例
类组件 对比 函数组件
实现 state 状态修改、定时器、输入框信息打印、组件卸载
-
类组件 实现
src/index.js 暴露 root
import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; import { BrowserRouter } from "react-router-dom"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <BrowserRouter> <App /> </BrowserRouter> ); export default root;
import React, { Component } from "react"; import { createRef } from "react"; import root from "../../index";//引入root路径 export default class index extends Component { state = { count: 0, name: "tom", }; myRef = createRef(); componentDidMount() { this.timer = setInterval(() => { this.setState({ count: this.state.count + 1, }); }, 1000); } componentWillUnmount() { clearInterval(this.timer); } increment = () => { this.setState((state) => { return { count: state.count + 1, }; }); }; updateName = () => { this.setState({ name: "小明", }); }; unMount = () => { root.unmount(); }; showInputValue = () => { console.log(this.myRef.current.value); }; render() { return ( <div> <h4>数值为:{this.state.count}</h4> <button onClick={this.increment}>+1</button> <h4>名字:{this.state.name}</h4> <button onClick={this.updateName}>改名</button> <br /> <br /> <button onClick={this.unMount}>卸载组件</button> <br /> <br /> <input ref={this.myRef} type="text" /> <button onClick={this.showInputValue}>打印输入框信息</button> </div> ); } }
-
函数组件 实现
src/index.js 暴露 root
import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; import { BrowserRouter } from "react-router-dom"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <BrowserRouter> <App /> </BrowserRouter> ); export default root;
import { useState, useEffect, useRef } from "react"; import root from "../../index";//引入root路径 function Index() { const [count, setCount] = useState(0); const [name, setName] = useState("tom"); const myRef = useRef(); useEffect(() => { let timer = setInterval(() => { setCount((count) => count + 1); }, 1000); return () => { clearInterval(timer); }; }, []); function increment() { // setCount(count + 1);// 第一种写法 setCount((count) => { return count + 1; }); } function updateName() { setName("小明"); } function unMount() { root.unmount(); } function showInputValue() { console.log(myRef.current.value); } return ( <div> <h4>数值为:{count}</h4> <button onClick={increment}>+1</button> <h4>名字:{name}</h4> <button onClick={updateName}>改名</button> <br /> <br /> <button onClick={unMount}>卸载组件</button> <br /> <br /> <input ref={myRef} type="text" /> <button onClick={showInputValue}>打印输入框信息</button> </div> ); } export default Index;
-
组件实现效果图