十分钟快速使用 React18 + vite + TypeScript + antDesign 搭建一个前端框架

在这篇博客中,我将向读者们介绍如何使用 React18 + vite + TypeScript + antDesign搭建一个前端框架。React 是一种流行的 JavaScript 库,用于构建用户界面。vite是一个快速的前端构建工具,能够快速创建现代化的应用程序。TypeScript 是一种开源的编程语言,它可以帮助开发者在编写JavaScript 代码时减少错误。antDesign 是一个流行的 UI 库,提供了众多现成的组件可以让开发者更轻松地构建出漂亮的视图。在本博客结束时,读者将了解如何将这些技术组合在一起,创建出一个普普通通的前端框架。

本篇博客将分为以下几个步骤:

  • 准备工作:安装必需的软件和库
  • 创建一个新的项目
  • 安装 ReactantDesign
  • 配置 TypeScript
  • 构建应用程序
  • 创建自定义的 antDesign 组件
  • 集成 Redux
  • 使用路由和导航器

请注意,本篇文章的重点是搭建前端框架,因此我们不会涉及特定领域的业务逻辑。

准备工作:安装必需的软件和库

在开始之前,你需要在计算机上安装必要的工具和库。确保已经安装了 Node.js 和 npm。你可以到 Node.js 官方网站下载适合自己的安装文件,并进行安装。 安装完成后,你还需要全局安装 create-vite-app 和 TypeScript,可以直接在命令行工具中执行以下命令:

npm i -g create-vite-app typescript

创建一个新的项目

在安装完必要的软件后,我们需要用 create-vite-app 工具创建一个新项目。从命令行中运行以下命令:

create-vite-app my-app --template react-ts

这将会创建一个名为 my-app 的新项目,使用 react-ts 模板来初始化应用程序。这里我们使用 TypeScript 模板,可以帮助我们在编写代码时发现一些常见的错误。
命令执行完后,你应该可以看到一个文件夹 my-app 被创建出来了。进入 my-app 目录,执行以下命令开始项目:

cd my-app
npm i
npm run dev

这些命令将会跑起应用程序,并在浏览器中打开 localhost:3000 端口以供你访问。

安装 React 和 antDesign 库

我们的下一步是安装 ReactantDesign 库。在命令行中输入以下命令:

npm i react react-dom antd @types/react @types/react-dom

这将会安装最新的 ReactantDesign 库以及类型声明文件。请确保使用的版本是最新的,以便获得最佳的性能和最新功能。

按需加载antd

antd 默认支持基于 ES modulestree shaking,直接引入 import { Button } from 'antd'; 就会有按需加载的效果。

高级配置

目前我这边安装的最新antd版本是5.xx版本,如果项目中需要有主题配置等高级设置,可根据官方文档安装craco

配置 TypeScript

接下来,我们需要为 TypeScript 配置项目。创建 tsconfig.json 文件,并添加以下内容:

{
    
    
  "compilerOptions": {
    
    
    "target": "es6",
    "module": "esnext",
    "jsx": "react-jsx",
    "sourceMap": true,
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src"]
}

这个配置文件告诉 TypeScript 将代码编译为 ES6 模块,并使用 ReactJSX 语法。此外,我们还启用了严格模式,并支持 ES 模块的导入/导出功能。

构建应用程序

接下来,我们需要将 ReactantDesign 库集成到实际的应用程序中。
App.tsx 文件中,我们需要导入 ReactantDesign 组件:

import React from 'react';
import {
    
     Layout, Menu } from 'antd';
import './App.css';

const {
    
     Header, Content, Footer } = Layout;

function App() {
    
    
  return (
    <Layout className="layout">
      <Header>
        <div className="logo" />
        <Menu theme="dark" mode="horizontal" defaultSelectedKeys={
    
    ['2']}>
          <Menu.Item key="1">nav 1</Menu.Item>
          <Menu.Item key="2">nav 2</Menu.Item>
          <Menu.Item key="3">nav 3</Menu.Item>
        </Menu>
      </Header>
      <Content style={
    
    {
    
     padding: '0 50px' }}>
        <div className="site-layout-content">Content</div>
      </Content>
      <Footer style={
    
    {
    
     textAlign: 'center' }}>XXX XXXXX ©2023 Created by XXX XXXX</Footer>
    </Layout>
  );
}

export default App;

在这个例子中,我们导入了 antDesignLayoutMenu 组件,创建了一个基本的应用程序布局。
接下来,我们需要在 index.tsx 文件中将 React 组件渲染到页面上:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

这将会渲染 App 组件到页面上。现在,我们可以运行 npm run dev 命令以查看我们的更改。

npm run dev

创建自定义的 antDesign 组件

为了让我们的应用程序看起来更独特,并且符合具体的业务需求,我们可以创建自定义的 antDesign 组件。这里我们将会创建一个自定义的 Button 组件,这个组件将会是 antDesignButton 组件的改进版。
src/components 目录中,创建一个新文件 CustomButton.tsx,添加以下内容:

import React from 'react';
import {
    
     Button } from 'antd';
import {
    
     ButtonProps } from 'antd/lib/button';

interface CustomButtonProps extends ButtonProps {
    
    
  size?: 'small' | 'large' | 'default';
  shape?: 'round' | 'circle' | 'default';
}

const CustomButton: React.FC<CustomButtonProps> = ({
    
    
  size = 'default',
  shape = 'default',
  ...rest
}) => {
    
    
  let className = '';
  if (size !== 'default') {
    
    
    className += ` ${
      
      size}`;
  }
  if (shape !== 'default') {
    
    
    className += ` ${
      
      shape}`;
  }

  return <Button className={
    
    className.trim()} {
    
    ...rest} />;
};

export default CustomButton;

这个自定义的 Button 组件继承自 antDesignButton 组件,并且添加了两个新的 propssizeshape。这两个 props 用于定义按钮的大小和形状。
接下来,在 App.tsx 中使用 CustomButton 组件:

import React from 'react';
import {
    
     Layout, Menu } from 'antd';
import CustomButton from './components/CustomButton';
import './App.css';

const {
    
     Header, Content, Footer } = Layout;

function App() {
    
    
  return (
    <Layout className="layout">
      <Header>
        <div className="logo" />
        <Menu theme="dark" mode="horizontal" defaultSelectedKeys={
    
    ['2']}>
          <Menu.Item key="1">nav 1</Menu.Item>
          <Menu.Item key="2">nav 2</Menu.Item>
          <Menu.Item key="3">nav 3</Menu.Item>
          <CustomButton type="primary" size="large" shape="round">
            Sign up
          </CustomButton>
        </Menu>
      </Header>
      <Content style={
    
    {
    
     padding: '0 50px' }}>
        <div className="site-layout-content">Content</div>
      </Content>
      <Footer style={
    
    {
    
     textAlign: 'center' }}>XXX XXXX ©2023 Created by XXX XXXX</Footer>
    </Layout>
  );
}

export default App;

这里我们在应用程序头部菜单中添加了一个 Sign up 按钮,并且使用了我们自定义的 CustomButton 组件。

集成 Redux

现在,我们已经拥有了一个基本的应用程序,并且添加了自定义的 antDesign 组件。接下来,我们要考虑如何管理应用的状态。这里将介绍如何将 Redux 集成到我们的应用程序中。
首先,我们需要安装 Redux 库:

npm install redux react-redux @types/react-redux

接下来,在 src 目录下创建 redux 目录,并在其中创建 actionsreducersstoretypes 目录,以及 rootReducer.ts 文件。我们的 Redux 代码将被分布在这些目录中,并将 rootReducer.ts 文件作为统一入口。
types 目录下创建 types.ts 文件,该文件定义我们应用程序的所有状态:

import {
    
     ActionType } from 'typesafe-actions';

import * as actions from '../actions';

export type TodosAction = ActionType&lt;typeof actions&gt;;

export interface TodoItem {
    
    
  id: number;
  title: string;
  completed: boolean;
}

export interface TodosState {
    
    
  readonly todos: TodoItem[];
  readonly error?: string;
  readonly loading: boolean;
}

我们的应用程序状态将包含一个 todos 数组、一个 loading 标志符和可能的错误信息。接下来,我们需要创建 reducer。在 reducers/todosReducer.ts 文件中,添加以下内容:

import {
    
     TodosAction, TodosState } from '../types/types';
import {
    
     createReducer } from 'typesafe-actions';
import {
    
     addTodo, removeTodo, toggleTodo, fetchTodos, fetchTodosSuccess, fetchTodosFailure } from '../actions';

const initialState: TodosState = {
    
    
  todos: [],
  loading: false,
};

export const todosReducer = createReducer<TodosState, TodosAction>(initialState)
  .handleAction(addTodo, (state, action) => {
    
    
    const id = state.todos.reduce((maxId, todo) => Math.max(todo.id, maxId), -1) + 1;
    const title = action.payload;
    return {
    
    
      ...state,
      todos: [...state.todos, {
    
     id, title, completed: false }],
    };
  })
  .handleAction(removeTodo, (state, action) => ({
    
    
    ...state,
    todos: state.todos.filter((todo) => todo.id !== action.payload),
  }))
  .handleAction(toggleTodo, (state, action) => ({
    
    
    ...state,
    todos: state.todos.map((todo) =>
      todo.id === action.payload ? {
    
     ...todo, completed: !todo.completed } : todo
    ),
  }))
  .handleAction(fetchTodos, (state) => ({
    
    
    ...state,
    loading: true,
  }))
  .handleAction(fetchTodosSuccess, (state, action) => ({
    
    
    ...state,
    loading: false,
    todos: action.payload,
  }))
  .handleAction(fetchTodosFailure, (state, action) => ({
    
    
    ...state,
    loading: false,
    error: action.payload,
  }));

这个 reducer 处理了基于数组的 todos 对象的所有操作,包括添加、删除、切换和远程获取 todos。接下来,我们要将上面的 reducer 导入 rootReducer.ts 文件中:

import {
    
     combineReducers } from 'redux';
import {
    
     todosReducer } from './reducers/todosReducer';

const rootReducer = combineReducers({
    
    
  todos: todosReducer,
});

export type RootState = ReturnType<typeof rootReducer>;

export default rootReducer;

这里,我们将 todosReducer 和其他 possible reducer 合并成一个 rootReducer
接下来,我们需要创建 actions。在 actions/todosActions.ts 文件中,添加以下内容:

import {
    
     createAction } from 'typesafe-actions';
import {
    
     TodoItem } from '../types/types';

export const addTodo = createAction('ADD_TODO')<string>();
export const removeTodo = createAction('REMOVE_TODO')<number>();
export const toggleTodo = createAction('TOGGLE_TODO')<number>();
export const fetchTodos = createAction('FETCH_TODOS')();
export const fetchTodosSuccess = createAction('FETCH_TODOS_SUCCESS')<TodoItem[]>();
export const fetchTodosFailure = createAction('FETCH_TODOS_FAILURE')<string>();

这个文件导出了一些 actions,通过 createActions 工具创建。我们可以使用这些 actions 来通知 reducer 执行相应的操作。
接下来,我们需要创建 store。在 store/index.ts 文件中,添加以下内容:

import {
    
     createStore, applyMiddleware } from 'redux';
import {
    
     composeWithDevTools } from 'redux-devtools-extension';
import createSagaMiddleware from 'redux-saga';
import rootReducer from '../rootReducer';

const sagaMiddleware = createSagaMiddleware();

const store = createStore(
  rootReducer,
  composeWithDevTools(applyMiddleware(sagaMiddleware))
);

export default store;

这个文件创建了 Redux store,并将 sagaMiddleware 用作中间件。sagaMiddleware 是用于管理副作用的中间件,比如异步操作和处理 WebSocket 等。这里我们使用了 composeWithDevTools 工具来增强 store,这样我们可以在浏览器中使用 Redux 开发工具调试。
到目前为止,我们已经在应用程序中添加了 ReactantDesignTypeScriptRedux,这些都是构建框架的关键要素。

使用路由和导航器

接下来,我们要添加路由和导航器,以实现应用程序不同页面之间的切换。这里我们将使用 react-routerreact-router-dom 库。
首先,我们需要安装这两个库:

 npm install react-router react-router-dom @types/react-router-dom

接下来,在 App.tsx 文件上方添加以下 imports

 import {
    
     BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';

这里,我们导入了 RouterSwitchRouteLink 组件。Router 组件是 react-router 的基础组件,用于定义应用程序的主要路由。Link 组件用于在应用程序中定义导航链接。
接下来,在 App.tsx 文件中,将其中 LayoutHeaderMenuCustomButton 包裹在 Router 组件内:

import React from 'react';
import {
    
     Layout, Menu } from 'antd';
import './App.css';
import {
    
     BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
import CustomButton from './components/CustomButton';

const {
    
     Header, Content, Footer } = Layout;

function App() {
    
    
  return (
    <Router>
	    <Layout className="layout">
	    <Header>
	        <div className="logo" />
	        <Menu theme="dark" mode="horizontal" defaultSelectedKeys={
    
    ['-1']}>
	        <Menu.Item key="-1">
	            <Link to="/">Home</Link>
	        </Menu.Item>
	        <Menu.Item key="1">
	            <Link to="/about">About Us</Link>
	        </Menu.Item>
	        <Menu.Item key="2">
	            <Link to="/contact">Contact Us</Link>
	        </Menu.Item>
	        <CustomButton type="primary" size="large" shape="round">
	            Sign up
	        </CustomButton>
	        </Menu>
	    </Header>
	    <Content style={
    
    {
    
     padding: '0 50px' }}>
	        <div className="site-layout-content">
	        <Switch>
	            <Route path="/about">
	            <About />
	            </Route>
	            <Route path="/contact">
	            <Contact />
	            </Route>
	            <Route path="/">
	            <Home />
	            </Route>
	        </Switch>
	        </div>
	    </Content>
	    <Footer style={
    
    {
    
     textAlign: 'center' }}>XXX XXXX ©2023 Created by XXX XXXX</Footer>
	    </Layout>
	</Router>
  );
}

function Home() {
    
    
  return <h2>Home</h2>;
}

function About() {
    
    
  return <h2>About</h2>;
}

function Contact() {
    
    
  return <h2>Contact</h2>;
}

export default App;

这里,我们使用 SwitchRoute 组件定义了应用程序的不同路由,使其能够在点击菜单链接时正确切换到不同的页面。

我们现在已经完成了这个应用

猜你喜欢

转载自blog.csdn.net/zw7518/article/details/131056965