创建ts编写的react的项目
npx create-react-app react-typescript --template typescript
npx是什么?
- 避免安装全局模块,运行且不进行全局安装,下载到临时目录后再删除
- 调用项目内部的模块,egmocha只在项目中使用,而未全局安装,可以使用
node_modules/.bin/mocha --version
,也可使用npx mocha --version
import React from "react";// 传参和接收参数的时候都会接收提醒
interface IHelloProps {message: string;
}const Hello = (props: IHelloProps) => {return <h2>{props.message}</h2>
}export default Hello;
使用react内部定义的类型进行优化
type React.FC<P = {}> = React.FunctionComponent<P>
import React from "react";// 传参和接收参数的时候都会接收提醒
interface IHelloProps {message?: string;
}const Hello: React.FC<IHelloProps> = (props) => {return <h2>{props.message}</h2>
}Hello.defaultProps = {message: "Hello World"
}export default Hello;
01. useState
version 01 – useState基本使用
import React, {useState} from "react";const LikeButton: React.FC = () => {const [like, setLike] = useState(0);return (<button onClick={() => {setLike(like + 1)}}>{like}</button>)
}export default LikeButton;
version 02 – 用setState包裹对象
import React, {useState} from "react";const LikeButton: React.FC = () => {const [obj, setObj] = useState({like: 0, on: true});return (<button onClick={() => {setObj({like: obj.like + 1, on: !obj.on})}}>{obj.like}{obj.on ? "ON" : "OFF"}</button>)
}export default LikeButton;
version 03 – 基础变量分开,分别用useState包裹
import React, {useState} from "react";const LikeButton: React.FC = () => {const [like, setLike] = useState(0);const [on, setOn] = useState(false);return (<><button onClick={() => {setLike(like + 1)}}>{like}</button><button onClick={() => {setOn(!on)}}>{on ? "ON" : "OFF"}</button></>)
}export default LikeButton;
02. useEffect副作用函数
- 无需清除的Effect
第一次渲染和每次渲染之后都会执行 - 需要清除的Effect
import React, {useEffect} from React;const MouseTracker: React.FC = () => {const [position, setPosition] = useState({x: 0, y: 0});useEffect(() => {const updateMouse = (e: MouseEvent) => {setPosition({x: e.clientX, y: e.clientY});}document.addEventListener("click", updateMouse);return () => {document.removeEventListener("click", updateMouse);}})return (<p>X: {position.x}, Y: {position.y}</p>)
}export default MouseTracker;
自定义hook重构MouseTracker组件
useMousePosition.tsx
文件结构
import React, {useEffect} from React;// 1. 函数名称必须以use开头
// 2. 多个组件调用,state是隔离的,不会互相影响
const useMousePosition = () => {const [position, setPosition] = useState({x: 0, y: 0});useEffect(() => {const updateMouse = (e: MouseEvent) => {setPosition({x: e.clientX, y: e.clientY});}document.addEventListener("click", updateMouse);return () => {document.removeEventListener("click", updateMouse);}}, []);return position;
}export default useMousePosition;
MouseTracker.tsx
文件结构
import React, {useEffect} from React;
import useMousePosition from ".hooks//useMousePosition";const MouseTracker: React.FC = () => {const position = useMousePosition();return (<p>X: {position.x}, Y: {position.y}</p>)
}export default MouseTracker;
自定义URLLoder
- 提取组件公共操作部分
- hook得是一个函数
- hook的返回值是组件需要的
- hook中的state多个组件不共享
useURLLoader.tsx
- hook文件
import {useState, useEffect} from "react";
import axios from "axios";// url: 加载什么样的数据
// deps: 什么情况下触发数据的加载
const useURLLoader = (url: string, deps: any[] = []) => {const [data, setData] = useState<any>(null);const [loading, setLoading] = useState(false);// 请求数据useEffect(() => {setLoading(true); // 设置正在加载axios.get(url).then(result => {setData(result.data);})}, deps);return [data, loading];
}
export default useURLLoader;
在使用的组件中
import useURLLoader from "./hooks/useURLLoader";
interface IShowResult {message: string;status: string;
}
const App: React.FC = () => {const [data, loading] = useURLLoader("https://baidu.com/xxx", [variable...]);const dogResult = data as IShowResult;return ({loading ? <p> It's loading the message </p>: <img src={dogResult && dogResult.message}/>})
}
useRef
useRef值的修改不会影响组件的渲染
useRef包裹数值
const didMountRef = useRef(false);
useEffect(() => {if (didMountRef.current) {// 后边渲染的时候输出文字内容console.log("this is updated");}else {// 第一次渲染的时候修改值didMountRef.current = true;}
})
useRef包裹元素
const domRef = useRef<HTMLInputElement>(null);
useEffect(() => {if (domRef && domRef.current) {domRef.current.focus();}
})<input type="text" ref={domRef}/>
useContext
全局都可以拿到需要的变量,在ThemeContext的包裹下
interface IThemeProps {[key: string]: {color: string; background: string;}
}
const themes: IThemeProps = {'light': {color: "#000000",background: "#eeeeee"},'dark': {color: "#ffffff",background: "#222222"}
};
const ThemeContext = React.createContext(themes.light);
export ThemeContext;const App: React.FC = () => {return (<div className="app"><ThemeContext.Provider value={themes.light}></ThemeContext.Provider></div>)
}
// 导入
import {ThemeContext} from ".xxx/App.tsx";
import {useContext} from "react";const Comp: React.FC = () => {// 拿到const theme = useContext(ThemeContext);const style = {color: theme.color,background: theme.background}// 使用return (<div style={style}><p>Hello World</p></div>)
}
hook规则
- 只在最顶层使用hook,不在循环、条件、嵌套函数中调用hook
- 只在React函数中调用hook
其他hook
https://usehooks.com/