React——基础

发布于:2025-07-10 ⋅ 阅读:(90) ⋅ 点赞:(0)

React 基础

一、基础概念

声明式 UI,ui=render(state)

  • 声明式,定义状态,修改状态,将状态编写入 jsx
  • 组件化,(区块化,原子应用)
  • 虚拟 DOM,但是可以这样说,这个方案放在当下已经不是一个了不起的方案,FragmentDocument,没有虚拟 dom 的代表作 solidjs
  • 单向数据流。(Vue -> MVVM)
  • JSX,对开发者友好,但加重编译器的负担

二、组件化

// 类组件
class Welcome extends React.Component {
  render() {
    return <div>123</div>;
  }
}

// 函数组件
function Welcome() {
  return <div>123</div>;
}

三、状态

// 类组件
class Welcome extends React.Component {
  constructor() {
    this.state = {
      name: "heyi",
    };
  }
  render() {
    return <div>123</div>;
  }
}

// 函数组件
function Welcome() {
  const [count, setCount] = useState(0);
  return <div>123</div>;
}

四、属性

function Welcome(props) {
  return <div>{props.name}</div>;
}

五、项目初始化

项目初始化其实就是我们平常所说的工程化
在初始化时,我们需要考虑这个项目用什么语言(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>Document</title>
        </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 <div>123</div>;
      }
      
      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

jsx 全称是:javaScript and xml,在 javascript 代码中编写 html 代码是一种规范。因为规范是为编辑器设计的。

const element = <h1>Hello world!</h1>;

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
);

七、创建 React 组件的两种方式

函数式组件(推荐)

import React, { useState } from "react";

interface FCCBasicProps {
  name: string;
}

export const FCCBasic: React.FC<FCCBasicProps> = (props: FCCBasicProps) => {
  const [count, setCount] = useState(0);
  return (
    <div
      onClick={() => {
        setCount(count + 1);
      }}
    >
      Hello, Functional Component Basic! count: {count}
    </div>
  );
};

类组件(不推荐)

import React from "react";
export interface BasicProps {
  name: string;
}
export interface BasicState {
  count: number;
}

export class Basic extends React.Component<BasicProps, BasicState> {
  constructor(props: BasicProps) {
    super(props);
    this.state = {
      count: 0,
    };
  }
  render() {
    console.log(this.props.name);
    return (
      <div
        onClick={() => {
          this.setState({
            count: this.state.count + 1,
          });
        }}
      >
        Hello, Class Component Basic!{this.state.count}
      </div>
    );
  }
}

八、常用的 hooks

  1. useState: 用于状态管理
  2. useEffect: 用于数据获取、定时器、订阅、动画
  3. useContext: 用于数据共享
  4. useReducer: 状态管理
  5. useMemo: 缓存数据
  6. useRef: 获取 DOM 元素
  7. useCallback: 缓存函数

1、useState:用来修改状态值

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>
  );
};

2、useReducer:用来修改状态值,比 useState 更适合处理复杂逻辑

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>
  );
};

3、useContext:传递数据

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 (
//     <UserContext.Consumer>
//       {(value) => <div>{value.name}</div>}
//     </UserContext.Consumer>
//   );
// };

// 新版本基于 hooks 的写法
const Child = () => {
  const user = useContext(UserContext);
  return <div>{user.name}</div>;
};

4、useMemo: 缓存计算结果

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>
  );
};

5、useCallback:缓存函数

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>
  );
};

6、useEffect:副作用函数

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>
  );
};

7、useId:设置id

import React, { useId } from "react";

export const UseIdDemo = () => {
  const id = useId();
  return (
    <div>
      <label htmlFor={id}>Name</label>
      <input id={id} type="text" />
    </div>
  );
};

8、useImperativeHandle:用来给子组件绑定一些方法,让父组件可以直接调用子组件的方法

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>
  );
}

9、useTransition:主要用于在组件中实现非阻塞式更新(异步 UI 更新)

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>
  );
}

10、useDeferedValue:用于将状态更新延迟到更紧急的更新之后执行

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>
  );
};

12、useSyncExternalStore:是 React 官方推荐的方式,用于安全、高效地接入外部状态源,尤其适用于构建状态管理库或需要响应外部数据变化的场景

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>
  );
};

样式方案

  1. 内联方案 <i style={{color: "blue"}}>哈哈</i>
  2. module css
  3. css in js
  4. tailwind css

状态方案

  1. useState
  2. useReducer
  3. useContext
  4. useSyncExternalStore
  5. redux
  6. mobx
  7. zustand
  8. jotai
  9. recoil