首页 > web前端 > js教程 > 如何使用 React 和 Rest API 构建网站(React 基础知识解释)

如何使用 React 和 Rest API 构建网站(React 基础知识解释)

DDD
发布: 2024-11-08 03:05:02
原创
511 人浏览过

How to build a website using React and Rest APIs (React basics explained)

React 和 TypeScript 是用于构建可扩展、可维护和安全网站的强大框架。 React 提供了灵活且基于组件的架构,而 TypeScript 为 JavaScript 添加了静态类型,以实现干净且可读的代码。本文将指导您使用 React 和 TypeScript 设置一个简单的网站,涵盖入门所需的核心概念。

为什么选择 React 和 TypeScript?

TypeScript 在 JavaScript 开发人员中很受欢迎,因为它可以在开发过程中捕获错误并使代码更易于理解和重构。这两者非常适合构建现代、快速的网站和应用程序,并具有可扩展的可维护代码。

** 在 GitHub 上查看完整代码:https://github.com/alexiacismaru/techtopia/tree/main/frontend

基本的 React 概念以及如何使用它们来构建网站

让我们为一个名为 Techtopia 的虚构游乐园建立一个网站。我们将显示景点等元素以及它们在地图上的位置、登陆页面或加载页面。此外,我们还将允许添加/删除页面元素或基于变量搜索它们。

设置

通过将其复制到终端来创建一个空的 React 项目。

npm create vite@latest reactproject --template react-ts
登录后复制
登录后复制
登录后复制

然后运行空项目,浏览器窗口中将打开一个新选项卡。

cd reactproject
npm run dev
登录后复制
登录后复制
登录后复制

最终项目结构概述

reactproject/
├── node_modules/
├── public/
├── src/
│   ├── assets/
│   ├── components/
│   ├── context/
│   ├── hooks/
│   ├── model/
│   ├── services/
│   ├── App.css
│   ├── App.tsx
│   ├── index.css
│   ├── vite-env.d.ts
├── .gitignore
├── package.json
└── tsconfig.json
登录后复制
登录后复制
登录后复制

成分

组件是也可以重用的网页元素。它们可以是网页的一部分,例如页眉或页脚,也可以是整个页面,例如用户列表。它就像一个 JavaScript 函数,但返回一个渲染的元素。

export function Header() {
    return (
        <header>



<h3>
  
  
  JSX
</h3>

<p>JSX is JavaScript XML, allowing the user to write HTML-like code in .jsx files.<br>
</p>

<pre class="brush:php;toolbar:false"><button sx="{{padding:" color: onclick="{onClose}">X</button>
登录后复制
登录后复制

多伦多证券交易所

TSX 是包含 JSX 语法的 TypeScript 文件的文件扩展名。借助 TSX,您可以使用现有的 JSX 语法编写经过类型检查的代码。

interface RefreshmentStand {
    id: string;
    name: string;
    isOpen: boolean;
}

const Reshfresment = (props: RefreshmentStand) => {
  return (
    <div>
        <h1>{props.name}</h1>
        <p>{props.isOpen}</p>
    </div>
  );
};
登录后复制
登录后复制

碎片

片段将多个元素返回给组件。它对元素列表进行分组,而不创建额外的 DOM 节点。

我们可以使用它们从 Java 后端获取数据(查看如何从本文构建 Java 应用程序:https://medium.com/@alexia.csmr/using-bounded-contexts-to-build -a-java-application-1c7995038d30)。首先安装 Axios 并使用应用程序中的基本后端 URL。然后,我们将创建一个使用 GET 获取所有景点的片段。

import axios from 'axios'
import { POI } from '../model/POI'

const BACKEND_URL = 'http://localhost:8093/api'

export const getAttractions = async () => {
    const url = BACKEND_URL + '/attractions'
    const response = await axios.get<poi>(url)
    return response.data
}
</poi>
登录后复制
登录后复制

可以扩展到根据参数获取数据,POST,DELETE等

npm create vite@latest reactproject --template react-ts
登录后复制
登录后复制
登录后复制

状态

状态是一个 React 对象,包含有关组件的数据或信息。组件的状态可能会随着时间的推移而发生变化,当发生变化时,组件会重新渲染。

要根据参数从列表中获取单个元素,您可以使用 useParams() 挂钩。

cd reactproject
npm run dev
登录后复制
登录后复制
登录后复制

挂钩

如上所示,我使用了_useAttractions()和_useTagsAttractions()。它们是钩子,可以进行个性化以获得您想要的任何数据。在此示例中,他们根据 ID _或 _tags 获取景点。 Hooks 只能在 React 函数组件内部调用,只能在组件的顶层调用,并且不能是有条件的。

reactproject/
├── node_modules/
├── public/
├── src/
│   ├── assets/
│   ├── components/
│   ├── context/
│   ├── hooks/
│   ├── model/
│   ├── services/
│   ├── App.css
│   ├── App.tsx
│   ├── index.css
│   ├── vite-env.d.ts
├── .gitignore
├── package.json
└── tsconfig.json
登录后复制
登录后复制
登录后复制

isLoading 和 isError

为了获得更好的 UI 体验,最好让用户知道发生了什么,即元素正在加载,或者执行此操作时出现错误。它们首先在钩子中声明,然后在组件中引入。

export function Header() {
    return (
        <header>



<h3>
  
  
  JSX
</h3>

<p>JSX is JavaScript XML, allowing the user to write HTML-like code in .jsx files.<br>
</p>

<pre class="brush:php;toolbar:false"><button sx="{{padding:" color: onclick="{onClose}">X</button>
登录后复制
登录后复制

您还可以为更加自定义的网站创建单独的加载器或警报组件。

interface RefreshmentStand {
    id: string;
    name: string;
    isOpen: boolean;
}

const Reshfresment = (props: RefreshmentStand) => {
  return (
    <div>
        <h1>{props.name}</h1>
        <p>{props.isOpen}</p>
    </div>
  );
};
登录后复制
登录后复制

现在,当页面加载时,用户将在屏幕上看到特殊的动画。

映射项(列表和键)

如果你想显示列表中的所有元素,那么你需要映射所有元素。

import axios from 'axios'
import { POI } from '../model/POI'

const BACKEND_URL = 'http://localhost:8093/api'

export const getAttractions = async () => {
    const url = BACKEND_URL + '/attractions'
    const response = await axios.get<poi>(url)
    return response.data
}
</poi>
登录后复制
登录后复制

您可以在此处创建一个类型,以便稍后使用表单添加更多景点:

export const addAttraction = async (attractionData: Omit<poi>) => {
    const url = BACKEND_URL + '/addAttraction'
    const response = await axios.post(url, attractionData)
    return response.data
}

export const getAttraction = async (attractionId: string) => {
    const url = BACKEND_URL + '/attractions'
    const response = await axios.get<poi>(`${url}/${attractionId}`)
    return response.data
}

export const getAttractionByTags = async (tags: string) => {
    const url = BACKEND_URL + '/attractions'
    const response = await axios.get<poi>(`${url}/tags/${tags}`)
    return response.data
}
</poi></poi></poi>
登录后复制

添加项目

我们已经创建了所需的片段和挂钩,因此现在我们可以制作一个表单,用户可以在其中写入属性并向网页添加新的吸引力。该表单是使用 MUI 框架创建的。首先我将展示整个代码并分段解释。

const { id } = useParams()
const { isLoading, isError, attraction } = useAttraction(id!)
const { tag } = useParams()
const { isLoadingTag, isErrorTag, attractions } = useTagsAttractions(tag!)
登录后复制

如果您想让表单成为弹出窗口而不是单独的页面,请添加 isOpen()isClosed() 属性。 onSubmit() 是强制性的,因为这将触发 createPOI() 函数并将新对象添加到列表中。

import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
import {POI} from "../model/./POI.ts";
import { addAttraction, getAttractions } from '../services/API.ts'
import { useContext } from 'react'

export function useAttractions() {
    const queryClient = useQueryClient()
    const {
        isLoading: isDoingGet,
        isError: isErrorGet,
        data: attractions,
    } = useQuery({
        queryKey: ['attractions'],
        queryFn: () => getAttractions(),
    })

    const {
        mutate,
        isLoading: isDoingPost,
        isError: isErrorPost,
    } = useMutation((item: Omit<poi>) => addAttraction(item), {
        onSuccess: () => {
            queryClient.invalidateQueries(['attractions'])
        },
    });

    return {
        isLoading: isDoingGet || isDoingPost,
        isError: isErrorGet || isErrorPost,
        attractions: attractions || [],
        addAttraction: mutate
    }
}
</poi>
登录后复制

为了进行用户表单验证,我们将安装并导入 Zod。在这里声明输入需要什么格式以及是否有最小或最大长度等要求。

const navigate = useNavigate()
const { isLoading, isError, attractions, addAttraction } = useAttractions()

if (isLoading) {
    return <loader></loader>
}

if (isError) {
    return <alert severity="error">Error</alert>
}
登录后复制

在组件内部,我们需要实现提交和用户验证。

export default function Loader() {
    return (
        <div>
            <img alt="如何使用 React 和 Rest API 构建网站(React 基础知识解释)" src="https://media0.giphy.com/media/RlqidJHbeL1sPMDlhZ/giphy.gif?cid=6c09b9522vr2magrjgn620u5mfz1ymnqhpvg558dv13sd0g8&ep=v1_stickers_related&rid=giphy.gif&ct=s">
            <h3>Loading...</h3>
        </div>
    )
}
登录后复制

错误将在表单的 TextField 中与任何其他属性一起实现。

import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useAttractions } from '../hooks/usePOI.ts'
import { POI } from '../model/./POI.ts'

export default function Attractions() {
    const navigate = useNavigate()
    const { isLoading, isError, attractions, addAttraction } = useAttractions()

    return (
      <div>



<p>Create a separate file where you declare the Attraction element and its variables.<br>
</p>

<pre class="brush:php;toolbar:false">// ../model/POI.ts

export interface POI {
    id: string;
    name: string;
    description: string;
    tags: string;
    ageGroup: string;
    image: string;
}
登录后复制

确保表单可以在开始时关闭并提交。

export type CreatePOI = Omit<poi>; # id is automatically generated so we don't need to manually add it
</poi>
登录后复制

您可以在另一个组件中实现此弹出窗口。

import {CreatePOI} from "../model/./POI.ts";
import {z} from 'zod';
import {zodResolver} from "@hookform/resolvers/zod";
import {Controller, useForm} from "react-hook-form";
import {
    Box,
    Button,
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    TextField,
} from '@mui/material'

interface AttractionDialogProps {
    isOpen: boolean;
    onSubmit: (attraction: CreatePOI) => void;
    onClose: () => void;
}

const itemSchema: z.ZodType<createpoi> = z.object({
    name: z.string().min(2, 'Name must be at least 2 characters'),
    description: z.string(),
    tags: z.string(),
    ageGroup: z.string(),
    image: z.string().url(),
})

export function AddAttractionDialog({isOpen, onSubmit, onClose}: AttractionDialogProps) {
    const {
        handleSubmit,
        control,
        formState: {errors},
    } = useForm<createpoi>({
        resolver: zodResolver(itemSchema),
        defaultValues: {
            name: '',
            description: '',
            tags: '',
            ageGroup: '',
            image: '',
        },
    });

    return (
        <dialog open="{isOpen}" onclose="{onClose}">
            <form onsubmit="{handleSubmit((data)"> {
                    onSubmit(data)
                    onClose()
                })} 
            >
                <div>
                    <dialogtitle>Add attraction</dialogtitle>
                    <button onclick="{onClose}">
                        X
                    </button>
                </div>
                <dialogcontent>
                    <box>
                        <controller name="name" control="{control}" render="{({field})"> (
                                <textfield label="Name" error="{!!errors.name}" helpertext="{errors.name?.message}" required></textfield>
                            )}
                        />
                        <controller name="description" control="{control}" render="{({field})"> (
                                <textfield label="Description" error="{!!errors.description}" helpertext="{errors.description?.message}"></textfield>
                            )}
                        />
                        <controller name="tags" control="{control}" render="{({field})"> (
                                <textfield label="Tags" error="{!!errors.tags}" helpertext="{errors.tags?.message}" required></textfield>
                            )}
                        />
                        <controller name="ageGroup" control="{control}" render="{({field})"> (
                                <textfield label="Age group" error="{!!errors.ageGroup}" helpertext="{errors.ageGroup?.message}" required></textfield>
                            )}
                        />
                        <controller name="image" control="{control}" render="{({field})"> (
                                <textfield label="Image" error="{!!errors.image}" helpertext="{errors.image?.message}" required></textfield>
                            )}
                        />
                    </controller></controller></controller></controller></controller></box>
                </dialogcontent>
                <dialogactions>
                    <button type="submit" variant="contained">
                        Add
                    </button>
                </dialogactions>
            </form>
        </dialog>
    )
}
</createpoi></createpoi>
登录后复制

删除项目

创建一个使用 DELETE 的钩子并在组件中实现它。

npm create vite@latest reactproject --template react-ts
登录后复制
登录后复制
登录后复制
cd reactproject
npm run dev
登录后复制
登录后复制
登录后复制

在迭代项目列表时包含它。

reactproject/
├── node_modules/
├── public/
├── src/
│   ├── assets/
│   ├── components/
│   ├── context/
│   ├── hooks/
│   ├── model/
│   ├── services/
│   ├── App.css
│   ├── App.tsx
│   ├── index.css
│   ├── vite-env.d.ts
├── .gitignore
├── package.json
└── tsconfig.json
登录后复制
登录后复制
登录后复制

结论

将 React 与 TypeScript 结合使用使您能够构建易于维护和扩展的动态、安全的网站。 TypeScript 的类型检查可以防止运行时错误,而 React 基于组件的结构可以有效地组织项目。

以上是如何使用 React 和 Rest API 构建网站(React 基础知识解释)的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门推荐
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板