اسرار فرم های یک ظاهر طراحی شده (با استفاده از AWS Amplify Studio)

فرم ها به طرز فریبنده ای دشوار هستند. هنگامی که یک فرم برای وب سایت خود ایجاد می کنید، باید تصمیمات زیادی بگیرید. شما باید نگران اعتبار سنجی، ساختار و نحوه ارسال داده ها به باطن خود باشید. شما باید نحوه رسیدگی به خطاها و نحوه استایل و پیکربندی فرم خود را بیابید. شما باید مطمئن شوید که فرم های شما در دسترس هستند. با در نظر گرفتن این موضوع، AWS Amplify Studio با فرم ساز خود می تواند کمک کند!
در این پست درباره نحوه افزودن فرم جدید با استفاده از Amplify Studio که به منبع داده AWS Appsync متصل است صحبت خواهم کرد. ما به نحوه سفارشی کردن آن فرم با افزودن در حالت تاریک/روشن خواهیم پرداخت. ما به این خواهیم پرداخت که چگونه میتوانیم قوانین اعتبارسنجی را بیشتر سفارشی کنیم و پیامهای خطا را ویرایش کنیم! سپس موارد ارسالی خود را با نمایش نتایج با استفاده از کتابخانه JavaScript GraphQL API Amplify آزمایش می کنیم.
اگر می خواهید کد تکمیل شده را ببینید. لطفا این مخزن را بررسی کنید!
شروع شدن
با استفاده از استودیو Amplify یک فرم اولیه Todo ایجاد می کنیم.
برای شروع، وارد کنسول AWS خود شوید و AWS Amplify را جستجو کنید و روی آن کلیک کنید. اگر این اولین بار است که از Amplify استفاده می کنید، انتخاب کنید Get Started
و روی آن کلیک کنید Get started
دوباره در Amplify Studio. اگر قبلاً یک برنامه Amplify در این منطقه ایجاد کرده اید، می توانید کلیک کنید New app
→ Build an app
. نام برنامه را انتخاب کنید، کلیک کنید Confirm deployment
. پس از آن کلیک کنید Launch Studio
برای شروع!
اگر یک کاربر موجود Amplify Studio هستید، Studio را از برنامه موجود خود راه اندازی کنید. این ویژگی برای همه در دسترس است.
داده ها
در داخل Amplify Studio بیایید یک منبع داده ایجاد کنیم که بتوانیم با فرم خود استفاده کنیم. را کلیک کنید Data
در منو
کلیک Add model
و Todo را ایجاد کنید. فیلدهای تکمیل شده و عنوان را اضافه کنید.
پس از افزودن این مدل ها مطمئن شوید که روی آن کلیک کرده اید Save and Deploy
دکمه در گوشه سمت راست بالا استقرار ممکن است چند دقیقه طول بکشد.
پس از استقرار مدل، صفحهای با دستورالعملهایی برای وارد کردن آخرین پیکربندی کلاینت به برنامه React خود خواهید دید. حتماً دستور pull را کپی کنید.
راه اندازی برنامه Next.js
اکنون که دادهها و فرمهای خود را آماده کردهایم، میتوانیم اطلاعات را به برنامه موجود خود بکشیم. من فرض می کنم که شما قبلاً یک برنامه Next.js جدید ایجاد کرده اید. اگر نه، و در حال راه اندازی یک برنامه Next.js جدید هستید، مطمئن شوید که روتر App خاموش است.
برنامه خود را باز کنید و این کتابخانه ها را با مدیر بسته مورد علاقه خود نصب کنید.
$ npm install @aws-amplify/ui-react aws-amplify react-icons
اگر قبلاً نصب نشدهاید، مطمئن شوید که Amplify CLI را به صورت سراسری نصب کردهاید.
$ npm install @aws-amplify/cli -g
اگر پس از مدتی این اولین بار است که از Amplify استفاده می کنید، مطمئن شوید که به آخرین نسخه CLI ارتقا داده اید.
$ amplify upgrade
سپس، دستوری را که از آخرین بخش کپی کردهاید، گرفته و در ترمینال خود که آن را در ریشه پروژه Next.js خود اجرا میکند، قرار دهید.
$ amplify pull --appId <replace-this-with-your-id> --envName <replace-with-env-name>
اکنون باید چند فایل و دایرکتوری جدید در پروژه خود مشاهده کنید.
از آنجایی که ما با AppSync سروکار داریم، باید چند فایل Query GraphQL ایجاد کنید.
$ amplify codegen add
با این کار تعدادی فایل پرس و جو/اشتراک/جهش GraphQL مفید ایجاد می شود که بعداً در این آموزش از آنها استفاده خواهیم کرد.
بیایید Amplify را راه اندازی کنیم تا بتوانیم از فرم های جدید خود استفاده کنیم!
توجه: اگر از Next.js با روتر برنامه استفاده میکنید یا از Vite استفاده میکنید، ممکن است به پیکربندی کوچک دیگری نیاز داشته باشید. لطفاً راهنمای استفاده از Next.js یا Vite را دنبال کنید.
افزودن فرم ما و سفارشی کردن آن
بیایید شروع به تنظیم برنامه Next کنیم تا بتواند با AppSync Backend ما صحبت کند.
در فایل نقطه ورودی اصلی خود در برنامه خود، این خطوط را اضافه کنید تا Amplify را با سبک های صحیح پیکربندی کنید.
import { Amplify } from "aws-amplify";
import awsExports from "../aws-exports";
Amplify.configure(awsExports);
import "@aws-amplify/ui-react/styles.css";
در مرحله بعد، ما یک فایل تم ویژه اضافه می کنیم. این فایل برای سفارشی کردن تم های جهانی در سراسر برنامه شما استفاده می شود. در مورد ما، ما میخواهیم موضوع پیشفرض فرمهایمان را برای پشتیبانی از a لغو کنیم dark
حالت این defaultDarkModeOverride
این را برای ما اضافه خواهد کرد.
یک فایل جدید به نام ایجاد کنید theme.tsx
در شما src
پوشه
import { Theme, defaultDarkModeOverride } from "@aws-amplify/ui-react";
export const theme: Theme = {
name: "theme",
overrides: [defaultDarkModeOverride],
};
در مرحله بعد، این ارائه دهنده تم را به یک فایل Layout جدید اضافه می کنیم. در src/components
پوشه جدید ایجاد کنید Layout.tsx
فایل. داخل این فایل یک فایل جدید اضافه می کنیم colorMode
متغیر useState که از آن برای تغییر رنگ تم استفاده می کنیم.
این ThemeProvider
برنامه ما را احاطه می کند و قابلیت های قالب بندی را با توکن های طراحی برای برنامه ما ارائه می دهد. این توکن ها می توانند ظاهر و احساس برنامه ما را کاملاً تحت تأثیر قرار دهند. اسناد رسمی این موضوع را با جزئیات بیشتری مورد بحث قرار می دهد.
import { theme } from "@/theme";
import { ColorMode, ThemeProvider } from "@aws-amplify/ui-react";
import React from "react";
export default function Layout({ children }: React.PropsWithChildren) {
const [colorMode, setColorMode] = React.useState<ColorMode>("light");
return (
<ThemeProvider theme={theme} colorMode={colorMode}>
{children}
</ThemeProvider>
)
}
بیایید یک دکمه جابجایی اضافه کنیم تا کاربران بتوانند بین حالت تاریک و روشن انتخاب کنند. ما از مجموعه react-icons/md برای این نمادها استفاده خواهیم کرد.
import { theme } from "@/theme";
import { MdOutlineDarkMode, MdOutlineLightMode } from "react-icons/md";
import { ColorMode, Flex, ThemeProvider, ToggleButton, ToggleButtonGroup } from "@aws-amplify/ui-react";
import React from "react";
export default function Layout({ children }: React.PropsWithChildren) {
const [colorMode, setColorMode] = React.useState<ColorMode>("light");
return (
<ThemeProvider theme={theme} colorMode={colorMode}>
<Flex direction="column" gap="0" width="100vw" height="100vh" backgroundColor="background.primary">
<ToggleButtonGroup
value={colorMode}
size="small"
isExclusive
onChange={(value) => setColorMode(value as ColorMode)}
>
<ToggleButton value="light">
<MdOutlineLightMode />
</ToggleButton>
<ToggleButton value="dark">
<MdOutlineDarkMode />
</ToggleButton>
</ToggleButtonGroup>
{children}
</Flex>
</ThemeProvider>
)
}
این ToggleButtonGroup
از مجموعه ای از UI های اولیه ارائه شده توسط @aws-amplify/ui-react
کتابخانه این یک دکمه جابجایی به ظاهر زیبا ایجاد می کند. با هر کلیک دکمه جابجایی colorMode
تنظیم شده است و در به روز رسانی می شود ThemeProvider
. این باعث می شود صفحه نمایش بین حالت تاریک و روشن تغییر کند.
در نهایت، ما یک را اضافه می کنیم AppHeader
جزء برای کمک به چسباندن این طرح به گوشه سمت چپ بالا. ما همچنین یک نماد زیبا با استفاده از Icon
جزء ابتدایی
import { theme } from "@/theme";
import { MdOutlineDarkMode, MdOutlineLightMode } from "react-icons/md";
import {
ColorMode,
Flex,
Icon,
ThemeProvider,
ToggleButton,
ToggleButtonGroup,
} from "@aws-amplify/ui-react";
import React from "react";
function AppHeader({ children }: React.PropsWithChildren) {
return (
<Flex
as="header"
direction="row"
justifyContent="space-between"
alignItems="center"
padding="1rem"
boxShadow="small"
position="sticky"
top="0"
left="0"
width="100%"
backgroundColor="background.primary"
>
{children}
</Flex>
);
}
export default function Layout({ children }: React.PropsWithChildren) {
const [colorMode, setColorMode] = React.useState<ColorMode>("light");
return (
<ThemeProvider theme={theme} colorMode={colorMode}>
<Flex
direction="column"
gap="0"
width="100vw"
height="100vh"
backgroundColor="background.primary"
>
<AppHeader>
<Icon
color="brand.primary.60"
fontSize="xl"
paths={[
{
d: "M10.8484 4.19838C10.7939 4.2926 10.7939 4.40867 10.8484 4.50288L21.3585 22.6711C21.413 22.7653 21.5138 22.8233 21.6228 22.8233H23.9901C24.225 22.8233 24.3718 22.5696 24.2543 22.3666L12.5605 2.15225C12.4431 1.94925 12.1495 1.94925 12.0321 2.15225L10.8484 4.19838Z",
},
{
d: "M15.2084 22.6711C15.2629 22.7653 15.3636 22.8233 15.4726 22.8233H17.8461C18.081 22.8233 18.2278 22.5696 18.1104 22.3666L9.48857 7.46259C9.37113 7.25959 9.07755 7.25959 8.96011 7.46259C6.09213 12.4203 3.21732 17.4003 0.336955 22.3816C0.219574 22.5846 0.366371 22.8383 0.601212 22.8383H11.7185C11.9533 22.8383 12.1001 22.5846 11.9827 22.3816L10.8455 20.4158C10.791 20.3216 10.6903 20.2635 10.5813 20.2635H4.8952C4.77776 20.2635 4.70437 20.1367 4.76308 20.0352L9.0912 12.5534C9.14991 12.4519 9.29671 12.4519 9.35542 12.5534L15.2084 22.6711Z",
},
]}
/>
<ToggleButtonGroup
value={colorMode}
size="small"
isExclusive
onChange={(value) => setColorMode(value as ColorMode)}
>
<ToggleButton value="light">
<MdOutlineLightMode />
</ToggleButton>
<ToggleButton value="dark">
<MdOutlineDarkMode />
</ToggleButton>
</ToggleButtonGroup>
</AppHeader>
{children}
</Flex>
</ThemeProvider>
);
}
ما باید به روز رسانی کنیم _app.tsx
فایل تا طرح جدید ما برنامه را احاطه کند.
...
export default function App({ Component, pageProps }: AppProps) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
حالت تاریک را تغییر دهید و آن را در عمل ببینید.
قبل از:
بعد از:
اضافه کردن فرم ما و سفارشی کردن آنها
حالا بیایید فرم خود را به مسیر اصلی اضافه کنیم index.tsx
فایل در برنامه Next.js ما.
فرم را به صفحه وارد کنید
import TodoForm from "@/ui-components/TodoCreateForm";
export default function Home() {
return <TodoForm/>
}
طبق قرارداد، این فرم قبلاً به مدل AppSync که قبلاً ایجاد کردیم متصل است. در زیر روکش ها از چیزی به نام DataStore برای همگام سازی و ارسال داده ها به backend استفاده می کند.
ما می توانیم این فرم را به دلخواه شخصی سازی کنیم. بیایید ابتدا قانون اعتبارسنجی را به روز کنیم. فرض کنید نمی خواهیم کاربران در فضاهای خالی وارد شوند. یک چک برای آن اضافه می کنیم و یک پیام خطای سفارشی نمایش می دهیم.
<TodoForm
padding="0"
onValidate={{
title: (value, validateResponse) => {
if (value.trim().length === 0) {
return {
hasError: true,
errorMessage: "Please enter a value!",
};
}
return validateResponse;
},
}}
/>
با وجود این اعتبارسنجی، کاربران نمیتوانند ورودی خالی را بدون دریافت خطا ارسال کنند. منطق فرم ها بقیه موارد را مدیریت می کند و ورودی را نیز غیرفعال می کند.
تصور کنید که می خواهیم هر بار که کاربر با موفقیت کاری را ارسال کرد، پیامی را نشان دهیم. فرمهای تولید شده دارای کنترلکنندههایی هستند که میتوانید به آنها متصل شوید و به آنها گوش دهید. در این مثال، ما یک را ایجاد می کنیم showSuccess
متغیری که می توانیم از آن برای راه اندازی یک پیام هشدار استفاده کنیم که پس از دو ثانیه محو می شود.
const [showSuccess, setShowSuccess] = useState(false);
...
<TodoForm
padding="0"
onValidate={{
title: (value, validateResponse) => {
if (value.trim().length === 0) {
return {
hasError: true,
errorMessage: "Please enter a value!",
};
}
return validateResponse;
},
}}
onSuccess={() => {
setShowSuccess(true);
setTimeout(() => {
setShowSuccess(false);
}, 2000);
}}
/>
{showSuccess && <Alert variation="success">Todo added!</Alert>}
این onSuccess
کنترل کننده به محض اینکه فرم با موفقیت ارسال شد فعال می شود. سپس می توانیم یک هشدار نشان دهیم! این Alert
دیگری است @aws-amplify/ui-react
رابط کاربری اولیه
اکنون که راهی برای اضافه کردن کارهای انجام شده داریم، به راهی برای نشان دادن آنها نیاز داریم.
بیایید روشی را اضافه کنیم که همه کارها را در بر می گیرد. این از Amplify JS کتابخانه GraphQL API استفاده می کند.
import { API, graphqlOperation } from "aws-amplify";
import { GraphQLQuery, GraphQLSubscription } from "@aws-amplify/api";
import { ListTodosQuery, Todo, OnCreateTodoSubscription } from "@/API";
import { listTodos } from "@/graphql/queries";
...
const [todos, setTodo] = useState<Todo[]>([]);
const getTodos = async () => {
const allTodos = await API.graphql<GraphQLQuery<ListTodosQuery>>({
query: listTodos,
});
const filteredTodos = allTodos.data?.listTodos?.items
.filter((todo) => !todo?._deleted)
.sort(
(a, b) =>
new Date(a?.createdAt!).getTime() - new Date(b?.createdAt!).getTime()
);
setTodo(filteredTodos as Todo[]);
};
از آنجایی که ما برنامه خود را با استفاده از Studio و فرم ساز ایجاد کردیم، طبق قرارداد فرم های ما از DataStore و conflict resolution
در پس زمینه روشن شد حل تضاد یک منبع داده نسخهبندی شده ایجاد میکند که مدل داده شی را با ابرداده بهبود میبخشد. در حال حاضر، نمیتوانید هنگام استفاده از Form Builder و استودیو آن را خاموش کنید.
معنی آن این است که مدل داده ما دارای چند فیلد متا اضافی از جمله _deleted
و _version
. هنگامی که مدل ایجاد شد، اینها به طور خودکار به مدل داده ما اضافه می شوند. وقتی رکوردی را حذف میکنید، آنطور که معمولاً انتظار دارید، حذف نمیشود. در عوض، _deleted
فیلد تنظیم می شود true
و رکورد باقی می ماند این را در هنگام برخورد با داده ها در نظر داشته باشید conflict resolution
روشن شد. به همین دلیل است که ما باید رکوردها را با آن فیلتر کنیم _deleted
در کد ما روی true تنظیم شده است، به این ترتیب ما به طور تصادفی داده های حذف شده را نشان نمی دهیم.
خوب است بدانید که اگر تصمیم دارید برای هر رکوردی با استفاده از Amplify GraphQL API به روز رسانی یا حذف کنید، باید _version
در ورودی GraphQL چون حل تعارض روشن است. این _version
فیلد با هر تغییری که در رکورد رخ می دهد افزایش می یابد. شما باید این را پیگیری کنید _version
زمانی که بهروزرسانی میکنید یا موردی را حذف میکنید.
برای تضمین ترتیب صحیح، ما بر اساس مرتب سازی createdAt
زمان.
اکنون که راهی برای گرفتن داده ها داریم، یک اشتراک GraphQL ایجاد می کنیم که به محض بارگیری برنامه با استفاده از یک useEffect
.
import { API, graphqlOperation } from "aws-amplify";
import { GraphQLQuery, GraphQLSubscription } from "@aws-amplify/api";
import { ListTodosQuery, Todo, OnCreateTodoSubscription } from "@/API";
import { onCreateTodo } from "@/graphql/subscriptions";
import { useEffect, useState } from "react";
...
const [todos, setTodo] = useState<Todo[]>([]);
useEffect(() => {
getTodos();
const sub = API.graphql<GraphQLSubscription<OnCreateTodoSubscription>>(
graphqlOperation(onCreateTodo)
).subscribe({
next: ({ provider, value }) => {
setTodo((prevValue) => [
...prevValue,
value.data?.onCreateTodo as Todo,
]);
},
error: (error) => console.warn(error),
});
return () => sub.unsubscribe();
}, []);
ابتدا ماشه را فعال می کنیم getTodos
و سپس اشتراک ما را اجرا کنید. به محض ایجاد یک Todo جدید، اشتراک فعال می شود. سپس می توانیم از خود استفاده کنیم setTodo
برای ذخیره داده ها در آرایه در غیر این صورت، می توانیم تماس بگیریم getTodos
دوباره در هر تغییر اشتراک، با این حال به خاطر این پست، ما آن را دستکاری می کنیم todos
آرایه کنید و به جای آن کار جدید را به آن اضافه کنید.
بیایید همه اینها را در یک فایل جمع کنیم. من چند UI اولیه دیگر اضافه کرده ام تا کارها را آسان تر کنم از جمله a Collection
جزء که با آرایه برای نمایش داده ها در یک ردیف خوب استفاده می شود.
import {
Alert,
Card,
Collection,
Flex,
Heading,
Text,
useTheme,
} from "@aws-amplify/ui-react";
import TodoForm from "@/ui-components/TodoCreateForm";
import { API, graphqlOperation } from "aws-amplify";
import { GraphQLQuery, GraphQLSubscription } from "@aws-amplify/api";
import { ListTodosQuery, Todo, OnCreateTodoSubscription } from "@/API";
import { listTodos } from "@/graphql/queries";
import { onCreateTodo } from "@/graphql/subscriptions";
import { useEffect, useState } from "react";
export default function Home() {
const [showSuccess, setShowSuccess] = useState(false);
const [todos, setTodo] = useState<Todo[]>([]);
const getTodos = async () => {
const allTodos = await API.graphql<GraphQLQuery<ListTodosQuery>>({
query: listTodos,
});
const filteredTodos = allTodos.data?.listTodos?.items
.filter((todo) => !todo?._deleted)
.sort(
(a, b) =>
new Date(a?.createdAt!).getTime() - new Date(b?.createdAt!).getTime()
);
setTodo(filteredTodos as Todo[]);
};
useEffect(() => {
getTodos();
const sub = API.graphql<GraphQLSubscription<OnCreateTodoSubscription>>(
graphqlOperation(onCreateTodo)
).subscribe({
next: ({ provider, value }) => {
setTodo((prevValue) => [
...prevValue,
value.data?.onCreateTodo as Todo,
]);
},
error: (error) => console.warn(error),
});
return () => sub.unsubscribe();
}, []);
const { tokens } = useTheme();
return (
<Flex
direction="row"
height="100%"
width="100%"
justifyContent="stretch"
gap="0"
>
<Flex
direction="column"
gap="medium"
padding="xxl"
backgroundColor="background.primary"
>
<Text>New ToDo</Text>
<TodoForm
padding="0"
onValidate={{
title: (value, validateResponse) => {
if (value.trim().length === 0) {
return {
hasError: true,
errorMessage: "Please enter a value!",
};
}
return validateResponse;
},
}}
onSuccess={() => {
setShowSuccess(true);
setTimeout(() => {
setShowSuccess(false);
}, 2000);
}}
/>
{showSuccess && <Alert variation="success">Todo added!</Alert>}
</Flex>
<Flex
direction="column"
flex="1"
padding="xxl"
backgroundColor="background.secondary"
>
<Heading level={3}>List of Todos</Heading>
<Collection gap="small" type="list" items={todos}>
{(todo) => (
<Card
variation="elevated"
color={tokens.colors.brand.primary[100]}
marginTop="1rem"
padding="1rem"
key={todo.id}
textDecoration={todo?.completed ? "line-through" : ""}
>
{todo?.title}
</Card>
)}
</Collection>
</Flex>
</Flex>
);
}
بیایید در عمل به آن نگاهی بیندازیم:
و با حالت تاریک، پس از کلیک بر روی آیکون حالت تاریک!
خیلی چیزهای بیشتری می توانیم در اینجا انجام دهیم. میتوانیم راهی برای گرفتن کارهای موجود و حذف آنها و علامتگذاری کامل آنها اضافه کنیم. من آن تمرین را برای شما می گذارم!
حذف
پس از اتمام کار با برنامه، می توانید با اجرای amplify delete، تمام منابع خود را حذف کنید.
نتیجه
در این پست وبلاگ با فرمهای Amplify Studio، نحوه سفارشیسازی آنها و نحوه اضافه کردن پیامهای خطای اعتبارسنجی اضافی آشنا شدیم. اگر میخواهید درباره Amplify به طور کلی بیشتر بدانید، لطفاً اسناد رسمی را بررسی کنید. همچنین می توانید آموزش Amplify Studio را برای اطلاعات بیشتر در مورد نحوه استفاده از آن بررسی کنید.
لطفا اگر سوالی دارید به من اطلاع دهید، من در خدمت هستم ErikCH در توییتر!