React 和 TypeScript 是用于构建可扩展、可维护和安全网站的强大框架。 React 提供了灵活且基于组件的架构,而 TypeScript 为 JavaScript 添加了静态类型,以实现干净且可读的代码。本文将指导您使用 React 和 TypeScript 设置一个简单的网站,涵盖入门所需的核心概念。
TypeScript 在 JavaScript 开发人员中很受欢迎,因为它可以在开发过程中捕获错误并使代码更易于理解和重构。这两者非常适合构建现代、快速的网站和应用程序,并具有可扩展的可维护代码。
** 在 GitHub 上查看完整代码:https://github.com/alexiacismaru/techtopia/tree/main/frontend
让我们为一个名为 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
为了获得更好的 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中文网其他相关文章!