目录
扩展学习资料
React Hooks 编写函数组件
Hooks使命
Hooks解决了什么问题
Hooks原理
useState源码解析
mountState源码解析
Hooks应用
Hooks 实践
倒计时组件
练习
名称 |
链接 |
React Hooks 官方文档 |
Introducing Hooks – React |
useEffect 完整指南 |
useEffect 完整指南 — Overreacted |
render props
export default function App() {
return (
{name => }
);
}
HOC【高阶组件】
class Avatar extends Component{
render() {
return {this.props.name} ;
}
}
function HocAvatar(Component) {
return ()=> ;
}
export default HocAvatar(Avatar);
Hooks
import React, {useState} from "react";
export function HooksAvatar() {
const [name, setName] = useState("云");
return <>{name}>;
}
并不是复杂的diff逻辑,仅仅是一个数组arrays
Hooks的demo
import React, {useState} from 'react';
import {render} from 'react-dom';
function App() {
const [name, setName] = useState('云');
return (
{name}
);
}
useState(
initialState: (() => S) | S,
): [S, Dispatch>] {
currentHookNameInDec = 'useState';
mountHookTypesDev();
const prevDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcherOnMountInDEV;
try {
// 调用mountState(初始化值)
return mountState(initialState);
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
}
mountState方法内:
如果方法里面有多个useState方法,如何让这些按期望的顺序执行呢?
function mountState(
initialState: (() => S) | S,
): [S, Dispatch>] {
// 返回当前正在运行的hook对象
const hook = mountWorkInProgressHook();
if(typeof initialState === 'function') {
// 是函数,就执行函数,拿return 值
// $FlowFixMe: Flow doesn't like mixed types
initialState = initialState();
}
// 字符串,就赋值
hook.memoizedState = hook.baseState = initialState;
// 定义一个队列,相当于queue = {...}
const queue = (hook.queue = {
pending: null,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRebderedState: (initialState: any),
});
// 这个dispatch就是我们在外面拿到的哪个修改值的方法
const dispatch: Dispatch,>
= (queue.dispatch = (dispatchAction,bind(null, currentlyRenderingFiber, queue, ) : any));
// [name, setName] = useState(initialState)
return [hook.memoizedState, dispatch];
}
Hooks官方API
CountDown组件-1
倒计时组件在我们日常的开发中十分常见。我们就以这个组件的开发来实践Hooks。
const maxTine = 10;
const [countDownText, setCountDownText] = useState('获取验证码');
const [timerNum,setTimerNum] = useState(maxTime);
const [boolCountDown,setBoolCountDown] = useState(false);
const handleClick = () => {
// 开始倒计时
}
return (
)
CountDown组件-2
const refCountDown = useRef(null);// 挂载倒计时的载体
const handleClick = () => {
if(boolCountDown) {
setBoolCountDown(true);
}
};
refCountDown.current = () => { // 具体逻辑处理放在current属性上
if (timerNum > 0) {
setTimerNum(timerNum - 1);
} else {// 倒计时结束,重置状态
setTimerNum(maxTime);
setBoolCountDown(false);
setCountDownText('重新获取');
}
}
useEffect(()=>{
if(boolCountDown) { // true 开始倒计时
const timer = setInterval(()=>{
refCountDown.current();
}, 1000);
return () => clearInterval(timer);
}
}, [boolCountDown]); // 检测到boolCountDown变化,就会执行
Hooks完整版倒计时组件
import React, { useState, useEffect, useRef } from "react";
export default function CountDown() {
const maxTime = 60;
const [countDownText, setCountDownText] = useState("获取验证码");
const [timerNum, setTimerNum] = useState(maxTime);
const [boolCountDown, setBoolCountDown] = useState(false);
const refCountDown = useRef(null);
const handleClick = () => { // 按钮事件是否开启
if (!boolCountDown) {
setBoolCountDown(true);
}
};
refCountDown.current = () => { // 如果timerNum不绑定在这里,它不会实时变化
if (timerNum > 0) {
setTimerNum(timerNum - 1);
} else {
setTimerNum(maxTime);
setBoolCountDown(false);
setCountDownText("重新获取");
}
};
// const otherCountDown = () => {
// console.log(timerNum, "timerNum");
// setTimerNum((timerNum) => timerNum - 1);
// };
useEffect(() => {
if (boolCountDown) {
const timer = setInterval(() => {
// otherCountDown();
refCountDown.current();
}, 1000);
return () => clearInterval(timer);// 执行一次,就清空一下定时
}
}, [boolCountDown]); // 根据这个参数监控的,想当componentDidMount使用就置空参数,就会只执行一次
return (
);
}
1.用Hooks 实现一个倒计时组件
2.用class完成一个倒计时组件