React——基础

文章目录

React 基础

一、基础概念

声明式 UI,ui=render(state)

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

二、组件化

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

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

三、状态

jsx 复制代码
// 类组件
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>;
}

四、属性

jsx 复制代码
function Welcome(props) {
  return <div>{props.name}</div>;
}

五、项目初始化

项目初始化其实就是我们平常所说的工程化

在初始化时,我们需要考虑这个项目用什么语言(js、ts),打包(webpack、vite),编译(babel、swc、rspack、esbuild),技术栈 React

接下来如果是企业级项目,除了技术层内容考虑以外,还需要重点关注:流程化、自动化、规范化等。

  • 使用 vite 自己从零搭建

    • 1、安装依赖

      json 复制代码
      {
        "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 文件

      js 复制代码
      import { defineConfig } from "vite";
      import react from "@vitejs/plugin-react";
      
      export default defineConfig({
        plugins: [react()],
        server: {
          port: 3000,
        },
      });
    • 3、在项目根目录创建 index.html 文件

      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

      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

      tsx 复制代码
      import { useState } from "react";
      function App() {
        return <div>123</div>;
      }
      
      export default App;
    • 6、编写启动脚本

      json 复制代码
        "scripts": {
        "dev": "vite",
        "build": "vite build",
        "preview": "vite preview",
        "test": "echo \"Error: no test specified\" && exit 1"
      },
    • 7、启动项目

      bash 复制代码
        pnpm run dev
  • 使用脚手架,不用关心初始化的细节

    • vite

      bash 复制代码
      pnpm create vite react-vite-cli-demo --template react-ts
    • create-react-app

      bash 复制代码
      npx create-react-app react-cra-demo --template typescript

六、jsx

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

jsx 复制代码
const element = <h1>Hello world!</h1>;

jsx 通过编译器进行转化,babel(@babel/preset-react、plugin-transform-react-jsx)

通过 jsx 转化后,代码就变成 js 引擎可以执行的代码了。

js 复制代码
import { jsx as _jsx } from "react/jsx-runtime";
var element = _jsx("h1", {
  children: "Hello world!",
});

再在 react 运行时,通过 react 定义的 jsx 创建出 ReactElement

js 复制代码
return ReactElement(
  type,
  key,
  ref,
  undefined,
  undefined,
  getOwner(),
  props,
  undefined,
  undefined
);

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

函数式组件(推荐)

tsx 复制代码
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>
  );
};

类组件(不推荐)

tsx 复制代码
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:用来修改状态值

ts 复制代码
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 更适合处理复杂逻辑

ts 复制代码
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:传递数据

ts 复制代码
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: 缓存计算结果

ts 复制代码
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:缓存函数

ts 复制代码
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:副作用函数

ts 复制代码
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

ts 复制代码
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:用来给子组件绑定一些方法,让父组件可以直接调用子组件的方法

ts 复制代码
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 更新)

ts 复制代码
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:用于将状态更新延迟到更紧急的更新之后执行

ts 复制代码
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 官方推荐的方式,用于安全、高效地接入外部状态源,尤其适用于构建状态管理库或需要响应外部数据变化的场景

ts 复制代码
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
相关推荐
zwjapple1 小时前
docker-compose一键部署全栈项目。springboot后端,react前端
前端·spring boot·docker
像风一样自由20203 小时前
HTML与JavaScript:构建动态交互式Web页面的基石
前端·javascript·html
伍哥的传说3 小时前
React 各颜色转换方法、颜色值换算工具HEX、RGB/RGBA、HSL/HSLA、HSV、CMYK
深度学习·神经网络·react.js
aiprtem4 小时前
基于Flutter的web登录设计
前端·flutter
浪裡遊4 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
why技术4 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
GISer_Jing4 小时前
0704-0706上海,又聚上了
前端·新浪微博
止观止4 小时前
深入探索 pnpm:高效磁盘利用与灵活的包管理解决方案
前端·pnpm·前端工程化·包管理器
whale fall4 小时前
npm install安装的node_modules是什么
前端·npm·node.js
烛阴5 小时前
简单入门Python装饰器
前端·python