一.hook(钩子):(按照生命周期和功能进行封装)
优势:逻辑简化.
而“钩子”的意思,就是在事件传送到终点前截获并监控事件的传输,像个钩子钩上事件一样,并且能够在钩上事件时,处理一些自己特定的事件。
(1)要启用Hooks,所有React软件包都必须为16.8.0或更高版本.
(2)钩子是允许从功能组件(function component)“挂钩”React状态和生命周期功能的功能。钩子在类内部不起作用-它们允许你在没有类的情况下使用React.
(3)React提供了一些像useState这样的内置Hook。你还可以创建自定义Hook以在不同组件之间重用有状态行为.
(4)Hook是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook不能在class组件中使用——这使得你不使用 class也能使用 React。(我们不推荐把你已有的组件全部重写,但是你可以在新组件里开始使用 Hook。)(2020-5新更新解释)
二.hook规则
1.hook是JavaScript函数,但它们强加了两个额外的规则.
(1)只能在顶层调用Hooks。不要在循环,条件或嵌套函数中调用Hook.
(2)仅从React功能组件调用Hooks。不要从常规JavaScript函数中调用Hook.
三.基本hook-useState
1.useState语法:const [state,setState] = useState(initialState);)(里面封装的是state(对象),在用的时候.)
(1)返回一个有状态值,以及一个更新它的函数.
(2)在初始渲染期间,返回的状态(state)与作为第一个参数(initialState)传递的值相同.
(3)该setState功能用于更新状态。它接受一个新的状态值并排队重新呈现组件.
(4)setState(newState);
(5)在随后的重新渲染过程中,返回的第一个值useState将始终是应用更新后的最新状态.
例1:
shook.js:
import React, { useState } from 'react';
export function Shook() {
const [count, setCount] = useState(0);
return (
<div>
<h2 onClick={() => setCount(count + 1)}>useState的使用</h2>
<p>你点了{count}次</p>
</div>
)
}
最终效果图:
点击前:
点击后:
引用的是Shook函数名:
例2:
shook.js:
import React, { useState } from 'react';
export function Shook() {
const [a, seta] = useState(0);
const [count, setCount] = useState(
{ n: 0, stu: [{ id: 1, names: "aaa" }, { id: 2, names: "bbb" }, { id: 3, names: "ccc" }, { id: 4, names: "ddd" }] }
);
return (
<div>
<h2 onClick={() => seta(a + 1)}>useState的使用</h2>
<p>你点了{a}</p>
<ul>
{count.stu.map(v => <li key={v.id}>{v.names}</li>)}
</ul>
</div>
)
}
最终效果图:
点击前:
点击后:
例3:
shook.js:
import React, { useState, useEffect } from 'react';
export function Shook() {
const [count, setCount] = useState(
{ n: 0, stu: [{ id: 1, names: "aaa" }, { id: 2, names: "bbb" }, { id: 3, names: "ccc" }, { id: 4, names: "ddd" }] }
);
useEffect(() => {
count.n += 1;
setCount({ stu: count.stu, n: count.n });
}, [])
return (
<div>
<h2>useState的使用</h2>
<p>你点了{count.n}</p>
<ul>
{count.stu.map(v => <li key={v.id}>{v.names}</li>)}
</ul>
</div>
)
}
最终效果图:
基本hook-useEffect
1.useEffect语法:useEffect(didUpdate);
(1)接受包含命令式(可能是有效代码)的函数.
(2)函数组件(称为react的呈现阶段)的主体中不允许出现Mutations,subscriptions, timers, logging和其他副作用。这样做将导致混淆错误和不一致的用户界面.
(3)从React组件执行数据提取,订阅或手动更改DOM。我们将这些操作称为“副作用”(或简称为“效果”),因为它们会影响其他组件,并且在渲染过程中无法完成.
(4)Efifect Hook中的useEffect增加了在功能组件执行副作用的功能。它与React类中的componentDidMount,componentDidUpdate和componentWillUnmount具有相同的用途,但统一为单个API.
效果 | 注意 |
---|---|
每次渲染后都执行清理或者执行effect | 这可能会导致性能问题,比如两次渲染的数据完全一样 |
只运行一次的effect(仅在组件挂载和卸载时执行) | 这就告诉React你的 effect不依赖于props或 state中的任何值,所以它永远都不需要重复执行 |
React将对前一次渲染的count和后一次渲染的count进行比较。若相等React 会跳过这个 effect | 实现了性能的优化 |
例:
shook.js:
import React, { useState, useEffect } from 'react';
export function Teachers() {
const [tes, setTes] = useState({ teachers: [], loads: false });
useEffect(() => { getTeacher(); }, tes.teachers)
function getTeacher(){
let ts = fetch("http://www.qhdlink-student.top/student/coach.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: 'username=ljj&userpwd=12345678&userclass=53&type=2'
});
ts.then(res => res.json()).then(json => {
for (let v in json) {
tes.teachers.push(json[v]);
}
setTes({ teachers: tes.teachers, loads: true })
// tes.loads = ture;
// setTes({ teachers: tes.teachers, loads: tes.loads })
})
}
return (
<div>
<h2>师资力量</h2>
{!tes.loads ? <h3>加载中...</h3> : tes.teachers.map(v => <p key={v.id_coach}>{v.name_coach}</p>)}
</div>
)
}
例:
shook.js:
import React, { useState, useEffect,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();
}
}
export function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
效果图: