声明式 UI,ui=render(state)
// 类组件
class Welcome extends React.Component {
render() {
return 123;
}
}
// 函数组件
function Welcome() {
return 123;
}
// 类组件
class Welcome extends React.Component {
constructor() {
this.state = {
name: "heyi",
};
}
render() {
return 123;
}
}
// 函数组件
function Welcome() {
const [count, setCount] = useState(0);
return 123;
}
function Welcome(props) {
return {props.name};
}
项目初始化其实就是我们平常所说的工程化
在初始化时,我们需要考虑这个项目用什么语言(js、ts),打包(webpack、vite),编译(babel、swc、rspack、esbuild),技术栈 React
接下来如果是企业级项目,除了技术层内容考虑以外,还需要重点关注:流程化、自动化、规范化等。
使用 vite 自己从零搭建
1、安装依赖
{
"dependencies": {
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.6.0",
"vite": "^7.0.2"
}
}
2、编写 vite.config.js 文件
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
},
});
3、在项目根目录创建 index.html 文件
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
head>
<body>
<div id="root">div>
<script type="module" src="/src/main.js">script>
body>
html>
4、创建 src/main.js
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)
5、创建 App.tsx
import { useState } from "react";
function App() {
return 123;
}
export default App;
6、编写启动脚本
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"test": "echo \"Error: no test specified\" && exit 1"
},
7、启动项目
pnpm run dev
使用脚手架,不用关心初始化的细节
vite
pnpm create vite react-vite-cli-demo --template react-ts
create-react-app
npx create-react-app react-cra-demo --template typescript
jsx 全称是:javaScript and xml,在 javascript 代码中编写 html 代码是一种规范。因为规范是为编辑器设计的。
const element = Hello world!
;
jsx 通过编译器进行转化,babel(@babel/preset-react、plugin-transform-react-jsx)
通过 jsx 转化后,代码就变成 js 引擎可以执行的代码了。
import { jsx as _jsx } from "react/jsx-runtime";
var element = _jsx("h1", {
children: "Hello world!",
});
再在 react 运行时,通过 react 定义的 jsx 创建出 ReactElement
return ReactElement(
type,
key,
ref,
undefined,
undefined,
getOwner(),
props,
undefined,
undefined
);
import React, { useState } from "react";
interface FCCBasicProps {
name: string;
}
export const FCCBasic: React.FC = (props: FCCBasicProps) => {
const [count, setCount] = useState(0);
return (
{
setCount(count + 1);
}}
>
Hello, Functional Component Basic! count: {count}
);
};
import React from "react";
export interface BasicProps {
name: string;
}
export interface BasicState {
count: number;
}
export class Basic extends React.Component {
constructor(props: BasicProps) {
super(props);
this.state = {
count: 0,
};
}
render() {
console.log(this.props.name);
return (
{
this.setState({
count: this.state.count + 1,
});
}}
>
Hello, Class Component Basic!{this.state.count}
);
}
}
import React, { useState } from "react";
interface UseStateDemoProps {}
export const UseStateDemo: React.FC<UseStateDemoProps> = () => {
const [count, setCount] = useState(0);
return (
<div onClick={() => setCount((c) => c + 1)}>
Hello, Functional Component UseStateDemo!{count}
</div>
);
};
import React, { useReducer } from "react";
type INCREMENT = "increment";
type DECREMENT = "decrement";
type Action = {
type: INCREMENT | DECREMENT;
};
type State = {
count: number;
};
interface ReducerProps {}
const reducer = (state: State, action: Action) => {
switch (action.type) {
case "increment":
return { ...state, count: state.count + 1 };
case "decrement":
return { ...state, count: state.count - 1 };
default:
return state;
}
};
export const UseReducerDemo: React.FC<ReducerProps> = () => {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div onClick={() => dispatch({ type: "increment" })}>
Hello,Functional Component useReducerDemo{state.count}
</div>
);
};
import React, { useContext } from "react";
interface UseContextProps {}
// 一定要结合 Context
const UserContext = React.createContext({ name: "default" });
// 提供者和消费者
export const UseContextDemo: React.FC<UseContextProps> = () => {
return (
<UserContext.Provider value={{ name: "jack" }}>
<Child />
</UserContext.Provider>
);
};
// 老版本写法
// const Child = () => {
// return (
//
// {(value) => {value.name}}
//
// );
// };
// 新版本基于 hooks 的写法
const Child = () => {
const user = useContext(UserContext);
return <div>{user.name}</div>;
};
import React, { useMemo, useState } from "react";
interface UseMemoProps {}
export const UseMemoDemo: React.FC<UseMemoProps> = () => {
const [count, setCount] = useState(0);
const [price, setPrice] = useState(0);
// 这个时候我想计算一个 Count 的二倍数,并且我们假设这个计算非常复杂,只在count更新时重新计算
const doubleCount = useMemo(() => {
console.log("只有count改变时才计算...");
return count * 2;
}, [count]);
return (
<div
onClick={() => {
if (price % 2 === 0) {
setCount((c) => c + 1);
}
setPrice((p) => p + 1);
}}
>
{doubleCount}----{price}
</div>
);
};
import React, { useCallback, useState } from "react";
interface UseCallbackProps {}
export const UseCallbackDemo: React.FC<UseCallbackProps> = () => {
const [count, setCount] = useState(0);
const [price, setPrice] = useState(0);
// 只有count发生变化后才重新创建函数
const handleClick = useCallback(() => {
console.log("~ handleClick ~ count: ", count);
}, [count]);
return (
<div onClick={handleClick}>
UseCallbackDemo,count:{count}-------{price}
<div
onClick={() => {
setCount((c) => c + 1);
}}
>
+ count
</div>
<div
onClick={() => {
setPrice((c) => c + 1);
}}
>
+ price
</div>
</div>
);
};
import React, { useEffect, useState } from "react";
export const UseEffectDemo: React.FC = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("useEffect");
document.title = `you clicked ${count} times`;
// 返回一个方法用来清除副作用
return () => {
console.log("clean up");
};
}, [count]);
return (
<div>
<p>UseEffectDemo</p>
<button onClick={() => setCount((c) => c + 1)}>click me</button>
</div>
);
};
import React, { useId } from "react";
export const UseIdDemo = () => {
const id = useId();
return (
<div>
<label htmlFor={id}>Name</label>
<input id={id} type="text" />
</div>
);
};
import React, { forwardRef, useImperativeHandle, useRef } from "react";
interface FancyInputHandle {
focus: () => void;
select: () => void;
}
// 但如果你希望父组件可以调用子组件中定义的方法(而不是直接访问 DOM),就需要使用 useImperativeHandle 来定制 ref 的内容。
const FancyInput = forwardRef<FancyInputHandle>((props, ref) => {
const inputRef = useRef<HTMLInputElement>(null);
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current?.focus();
},
select: () => {
inputRef.current?.select();
},
}));
return <input ref={inputRef} />;
});
export function UseImperativeHandleDemo() {
const inputRef = useRef<HTMLInputElement>(null);
return (
<div>
<FancyInput ref={inputRef} />
<button
onClick={() => {
inputRef.current?.focus();
}}
>
Focus the input
</button>
</div>
);
}
import React, { useState, useTransition } from "react";
export function UseTransitionDemo() {
const [isPending, startTransition] = useTransition();
const [count, setCount] = useState(0);
const handleClick = () => {
startTransition(() => {
setCount((c) => c + 1);
});
};
return (
<div>
<button onClick={handleClick}>Increment</button>
{isPending ? "Loading..." : <p>{count}</p>}
</div>
);
}
import React, { useDeferredValue } from "react";
export const UseDeferedValueDemo: React.FC = () => {
const [text, setText] = React.useState("");
const deferredText = useDeferredValue(text);
return (
<div>
<input value={text} onChange={(e) => setText(e.target.value)} />
<div>{deferredText}</div>
</div>
);
};
import React, { useSyncExternalStore } from "react";
function useWindowWidth() {
return useSyncExternalStore(
(cb) => {
window.addEventListener("resize", cb);
return () => window.removeEventListener("resize", cb);
},
() => window.innerWidth,
() => window.innerWidth
);
}
export const UseSyncExternalStoreDemo: React.FC = () => {
const width = useWindowWidth();
return (
<div>
<div>window width: {width} </div>
</div>
);
};
哈哈