Как создавать динамические многоэтапные формы с помощью Formik

Формы представляют собой раздел документа, используемый для ввода данных пользователем. Надежный компонент формы не только содержит поля ввода, но также обрабатывает состояние формы, проверку, обработку ошибок и отправку формы. Formik — это библиотека форм React с открытым исходным кодом, используемая для создания масштабируемых компонентов форм, от простых до сложных, с меньшим количеством шаблонов и простотой. В этой статье вы узнаете, как работает Formik и как создать сложную многоэтапную форму React с динамическими полями ввода.

Что такое Формик?

Formik — это бесплатная библиотека форм React и React Native с открытым исходным кодом, используемая для создания полей формы с меньшим количеством шаблонов при обработке процедур формы:

  1. Управление состоянием формы.
  2. Подача формы.
  3. Проверка формы и отображение сообщений об ошибках.

Если вы знакомы с React и формами, вы можете выполнить каждую из упомянутых задач самостоятельно. Однако Formik обрабатывает весь этот метод масштабируемым, высокопроизводительным и простым способом. Создание форм любого уровня сложности станет проще простого с Formik.

За кулисами Formik — это просто React state и props , ничего лишнего. Это упрощает отладку и тестирование компонента формы, который вы создаете с помощью Formik.

Создание сложной формы Formik

В этом разделе вы узнаете, как использовать расширенные функции компонентов Formik, например, <FieldArray/>для создания сложной формы.

Первым шагом является создание проекта реакции. Запустите приведенные ниже команды в своем терминале, чтобы создать проект и установить необходимые зависимости:

npx create-react-app formik-project
cd formik-project
npm install formik yup @mui/material @emotion/react @emotion/styled formik-material-ui
npm start

Formik предлагает компоненты на базе React Context : <Formik />, <Form />, <Field />и <ErrorMessage />. Эти компоненты используют React Context для связи с состоянием/методами формы и делают шаблон формы менее сложным.

Перейдите src/App.jsи измените его с помощью блока кода ниже:

import React from "react";
import { Formik, Form, Field } from "formik";
import { Container, Card, CardContent, Typography, Grid, Button } from "@mui/material";
import { TextField } from "formik-material-ui";

const App = () => {
  return (
    <Container sx={{ bgcolor: "#87c1ff4d", paddingY: 3, marginTop: 5 }}>
      <Typography variant="h3" align="center" component="h2">
        Formik Form
      </Typography>
      <Card sx={{ marginTop: 2 }}>
        <CardContent sx={{ paddingY: 10, paddingX: 5 }}>
          <Formik>
            <Form>
              <Grid container spacing={2}>
                <Grid item md={6}>
                  <Field fullWidth name="firstname" component={TextField} label="First Name" />
                </Grid>
                <Grid item md={6}>
                  <Field fullWidth name="lastname" component={TextField} label="Last Name" />
                </Grid>
              </Grid>
              <Grid container spacing={2}>
                <Grid item xs={12}>
                  <Typography variant="h6" component="h2">
                    Add Social Links
                  </Typography>
                </Grid>
                  <Grid item md={5}>
                    <Field fullWidth name="linkname" component={TextField} label="Link Name" />
                  </Grid>
                  <Grid item md={5}>
                    <Field fullWidth name="linkurl" component={TextField} label="Link URL" />
                  </Grid>
                  <Grid item md={2}>
                    <Button variant="outlined" color="error">
                      Delete
                    </Button>
                  </Grid>
                <Grid item>
                  <Button variant="outlined" >Add Link</Button>
                </Grid>
              </Grid>
            </Form>
          </Formik>
        </CardContent>
      </Card>
    </Container>
  );
};

export default App;

У вас должна быть простая форма на localhost:3000:

1 простая форма Formik

Создание пользовательского степпера формы

Цель состоит в том, чтобы разделить форму на двухэтапную форму, создать новый файл src/FormStepper.jsxи вставить приведенный ниже блок кода, чтобы создать собственный компонент шагового двигателя:

import React, { useState } from "react";
import { Form } from "formik";
import { Button, Stack, Step, StepLabel, Stepper } from "@mui/material";

export const FormStepper = ({ children }) => {
  const stepsArray = React.Children.toArray(children);
  const [step, setStep] = useState(0);
  const currentStep = stepsArray[step];

  return (
    <Form>
      <Stepper alternativeLabel activeStep={step} sx={{ marginBottom: 5 }}>
        {stepsArray.map((child, index) => (
          <Step key={child.props.label} completed={step > index}>
            <StepLabel>{child.props.label}</StepLabel>
          </Step>
        ))}
      </Stepper>
      {currentStep}
      <Stack direction="row" spacing={2} sx={{ marginTop: 5 }}>
        <Button
          variant="outlined"
          onClick={() => {
            step === 0 ? setStep(1) : setStep(0);
          }}
        >
          {step === 0 ? "Next" : "Back"}
        </Button>
        {step === 1 && (
          <Button variant="contained" type="submit">
            Submit
          </Button>
        )}
      </Stack>
    </Form>
  );
};

Этот компонент будет оболочкой формы, созданной в src/App.jsнем, и будет показывать шаг за шагом. Перейдите src/App.jsи замените <Form>компонент новым <FormStepper>компонентом:

import { FormStepper } from "./FormStepper"; // new import

const App = () => {
  return (
      <Formik>
         <FormStepper>
          {/* The rest of the form components goes here */}
         </FormStepper>
      </Formik>
)}

2 мультистеппера

Список полей динамической формы

Следующий подвиг — сделать социальные ссылки <Field/>динамическим списком. Для этого импортируйте <FieldArray />из Formik. Обновите src/App.jsблок кода ниже:

import React from "react";
import { Formik, Field, FieldArray } from "formik";
import { Container, Card, CardContent, Typography, Grid, Button } from "@mui/material";
import { TextField } from "formik-material-ui";
import { FormStepper } from "./FormStepper";

const App = () => {
  const linksGroup = { linkname: "", linkurl: "" };

  return (
    <Container sx={{ bgcolor: "#87c1ff4d", paddingY: 3, marginTop: 5 }}>
      <Typography variant="h3" align="center" component="h2">
        Formik Form
      </Typography>
      <Card sx={{ marginTop: 2 }}>
        <CardContent sx={{ paddingY: 10, paddingX: 5 }}>
          <Formik
            initialValues={{
              firstname: "",
              lastname: "",
              links: [linksGroup],
            }}
            onSubmit={async (values, actions) => {
              alert(JSON.stringify(values, null, 2));
            }}
          >
            {({ values }) => (
              <FormStepper>
                <Grid container spacing={2}>
                  <Grid item md={6}>
                    <Field fullWidth name="firstname" component={TextField} label="First Name" />
                  </Grid>
                  <Grid item md={6}>
                    <Field fullWidth name="lastname" component={TextField} label="Last Name" />
                  </Grid>
                </Grid>
                <FieldArray name="links">
                  {({ push, remove }) => (
                    <Grid container spacing={2} sx={{ marginTop: 2, paddingX: 2 }}>
                      <Grid item xs={12}>
                        <Typography variant="h6" component="h2">
                          Add Social Links
                        </Typography>
                      </Grid>
                      {values.links.map((_, index) => (
                        <>
                          <Grid item md={5}>
                            <Field fullWidth name={`links.${index}.linkname`} component={TextField} label="Link Name" />
                          </Grid>
                          <Grid item md={5}>
                            <Field fullWidth name={`links.${index}.linkurl`} component={TextField} label="Link URL" />
                          </Grid>
                          {index > 0 && (
                            <Grid item md={2}>
                              <Button variant="outlined" color="error" onClick={() => remove(index)}>
                                Delete
                              </Button>
                            </Grid>
                          )}
                        </>
                      ))}{" "}
                      <Grid item xs={12}>
                        <Button variant="outlined" onClick={() => push(linksGroup)}>
                          Add Link
                        </Button>
                      </Grid>
                    </Grid>
                  )}
                </FieldArray>
              </FormStepper>
            )}
          </Formik>
        </CardContent>
      </Card>
    </Container>
  );
};

export default App;

<FieldArray />— это компонент, помогающий манипулировать массивами или списками. Он получает свойство name, содержащее путь к ключу в values, содержащем нужный массив. Через свойства компонент предоставляет вам доступ к вспомогательным методам массива. В приведенном выше блоке кода методы pushи removeиспользуются для добавления и удаления элементов из linksмассива.

3 поля массива

Добавить проверки

Теперь, когда компонент формы имеет все необходимые функции, пришло время добавить проверки. Yup будет использоваться для добавления проверок. Импортируйте из yupбиблиотеки в src/App.js:

import { array, object, string } from "yup"; // new import

Компонент Formikполучает validationSchemaреквизит, который представляет собой объект, содержащий проверки для полей формы. Скопируйте и вставьте блок кода ниже и добавьте его в качестве реквизита для Formikкомпонента.

validationSchema={object({
    firstname: string().required("First Name is required"),
    lastname: string().required("Last Name is required"),
    links: array(
    object({
       linkname: string().required("Link Name is required"),
       linkurl: string().required("Link URL is required"),
       })
       ),
})}

4 Финальный проект

Вывод

Formik зарекомендовал себя как надежная, масштабируемая и высокопроизводительная библиотека реагирования для создания форм: за последний год было скачано более 2 миллионов раз . В этой статье была построена сложная форма. Formik предлагает гибкость и позволяет нам создавать настраиваемые компоненты шагового двигателя. Yup хорошо работает с Formik, также можно использовать пользовательские проверки.

Ссылка: https://blog.openreplay.com/dynamic-multi-step-forms-with-formik

#formik #реагировать #reactjs

What is GEEK

Buddha Community

Как создавать динамические многоэтапные формы с помощью Formik

Как создавать динамические многоэтапные формы с помощью Formik

Формы представляют собой раздел документа, используемый для ввода данных пользователем. Надежный компонент формы не только содержит поля ввода, но также обрабатывает состояние формы, проверку, обработку ошибок и отправку формы. Formik — это библиотека форм React с открытым исходным кодом, используемая для создания масштабируемых компонентов форм, от простых до сложных, с меньшим количеством шаблонов и простотой. В этой статье вы узнаете, как работает Formik и как создать сложную многоэтапную форму React с динамическими полями ввода.

Что такое Формик?

Formik — это бесплатная библиотека форм React и React Native с открытым исходным кодом, используемая для создания полей формы с меньшим количеством шаблонов при обработке процедур формы:

  1. Управление состоянием формы.
  2. Подача формы.
  3. Проверка формы и отображение сообщений об ошибках.

Если вы знакомы с React и формами, вы можете выполнить каждую из упомянутых задач самостоятельно. Однако Formik обрабатывает весь этот метод масштабируемым, высокопроизводительным и простым способом. Создание форм любого уровня сложности станет проще простого с Formik.

За кулисами Formik — это просто React state и props , ничего лишнего. Это упрощает отладку и тестирование компонента формы, который вы создаете с помощью Formik.

Создание сложной формы Formik

В этом разделе вы узнаете, как использовать расширенные функции компонентов Formik, например, <FieldArray/>для создания сложной формы.

Первым шагом является создание проекта реакции. Запустите приведенные ниже команды в своем терминале, чтобы создать проект и установить необходимые зависимости:

npx create-react-app formik-project
cd formik-project
npm install formik yup @mui/material @emotion/react @emotion/styled formik-material-ui
npm start

Formik предлагает компоненты на базе React Context : <Formik />, <Form />, <Field />и <ErrorMessage />. Эти компоненты используют React Context для связи с состоянием/методами формы и делают шаблон формы менее сложным.

Перейдите src/App.jsи измените его с помощью блока кода ниже:

import React from "react";
import { Formik, Form, Field } from "formik";
import { Container, Card, CardContent, Typography, Grid, Button } from "@mui/material";
import { TextField } from "formik-material-ui";

const App = () => {
  return (
    <Container sx={{ bgcolor: "#87c1ff4d", paddingY: 3, marginTop: 5 }}>
      <Typography variant="h3" align="center" component="h2">
        Formik Form
      </Typography>
      <Card sx={{ marginTop: 2 }}>
        <CardContent sx={{ paddingY: 10, paddingX: 5 }}>
          <Formik>
            <Form>
              <Grid container spacing={2}>
                <Grid item md={6}>
                  <Field fullWidth name="firstname" component={TextField} label="First Name" />
                </Grid>
                <Grid item md={6}>
                  <Field fullWidth name="lastname" component={TextField} label="Last Name" />
                </Grid>
              </Grid>
              <Grid container spacing={2}>
                <Grid item xs={12}>
                  <Typography variant="h6" component="h2">
                    Add Social Links
                  </Typography>
                </Grid>
                  <Grid item md={5}>
                    <Field fullWidth name="linkname" component={TextField} label="Link Name" />
                  </Grid>
                  <Grid item md={5}>
                    <Field fullWidth name="linkurl" component={TextField} label="Link URL" />
                  </Grid>
                  <Grid item md={2}>
                    <Button variant="outlined" color="error">
                      Delete
                    </Button>
                  </Grid>
                <Grid item>
                  <Button variant="outlined" >Add Link</Button>
                </Grid>
              </Grid>
            </Form>
          </Formik>
        </CardContent>
      </Card>
    </Container>
  );
};

export default App;

У вас должна быть простая форма на localhost:3000:

1 простая форма Formik

Создание пользовательского степпера формы

Цель состоит в том, чтобы разделить форму на двухэтапную форму, создать новый файл src/FormStepper.jsxи вставить приведенный ниже блок кода, чтобы создать собственный компонент шагового двигателя:

import React, { useState } from "react";
import { Form } from "formik";
import { Button, Stack, Step, StepLabel, Stepper } from "@mui/material";

export const FormStepper = ({ children }) => {
  const stepsArray = React.Children.toArray(children);
  const [step, setStep] = useState(0);
  const currentStep = stepsArray[step];

  return (
    <Form>
      <Stepper alternativeLabel activeStep={step} sx={{ marginBottom: 5 }}>
        {stepsArray.map((child, index) => (
          <Step key={child.props.label} completed={step > index}>
            <StepLabel>{child.props.label}</StepLabel>
          </Step>
        ))}
      </Stepper>
      {currentStep}
      <Stack direction="row" spacing={2} sx={{ marginTop: 5 }}>
        <Button
          variant="outlined"
          onClick={() => {
            step === 0 ? setStep(1) : setStep(0);
          }}
        >
          {step === 0 ? "Next" : "Back"}
        </Button>
        {step === 1 && (
          <Button variant="contained" type="submit">
            Submit
          </Button>
        )}
      </Stack>
    </Form>
  );
};

Этот компонент будет оболочкой формы, созданной в src/App.jsнем, и будет показывать шаг за шагом. Перейдите src/App.jsи замените <Form>компонент новым <FormStepper>компонентом:

import { FormStepper } from "./FormStepper"; // new import

const App = () => {
  return (
      <Formik>
         <FormStepper>
          {/* The rest of the form components goes here */}
         </FormStepper>
      </Formik>
)}

2 мультистеппера

Список полей динамической формы

Следующий подвиг — сделать социальные ссылки <Field/>динамическим списком. Для этого импортируйте <FieldArray />из Formik. Обновите src/App.jsблок кода ниже:

import React from "react";
import { Formik, Field, FieldArray } from "formik";
import { Container, Card, CardContent, Typography, Grid, Button } from "@mui/material";
import { TextField } from "formik-material-ui";
import { FormStepper } from "./FormStepper";

const App = () => {
  const linksGroup = { linkname: "", linkurl: "" };

  return (
    <Container sx={{ bgcolor: "#87c1ff4d", paddingY: 3, marginTop: 5 }}>
      <Typography variant="h3" align="center" component="h2">
        Formik Form
      </Typography>
      <Card sx={{ marginTop: 2 }}>
        <CardContent sx={{ paddingY: 10, paddingX: 5 }}>
          <Formik
            initialValues={{
              firstname: "",
              lastname: "",
              links: [linksGroup],
            }}
            onSubmit={async (values, actions) => {
              alert(JSON.stringify(values, null, 2));
            }}
          >
            {({ values }) => (
              <FormStepper>
                <Grid container spacing={2}>
                  <Grid item md={6}>
                    <Field fullWidth name="firstname" component={TextField} label="First Name" />
                  </Grid>
                  <Grid item md={6}>
                    <Field fullWidth name="lastname" component={TextField} label="Last Name" />
                  </Grid>
                </Grid>
                <FieldArray name="links">
                  {({ push, remove }) => (
                    <Grid container spacing={2} sx={{ marginTop: 2, paddingX: 2 }}>
                      <Grid item xs={12}>
                        <Typography variant="h6" component="h2">
                          Add Social Links
                        </Typography>
                      </Grid>
                      {values.links.map((_, index) => (
                        <>
                          <Grid item md={5}>
                            <Field fullWidth name={`links.${index}.linkname`} component={TextField} label="Link Name" />
                          </Grid>
                          <Grid item md={5}>
                            <Field fullWidth name={`links.${index}.linkurl`} component={TextField} label="Link URL" />
                          </Grid>
                          {index > 0 && (
                            <Grid item md={2}>
                              <Button variant="outlined" color="error" onClick={() => remove(index)}>
                                Delete
                              </Button>
                            </Grid>
                          )}
                        </>
                      ))}{" "}
                      <Grid item xs={12}>
                        <Button variant="outlined" onClick={() => push(linksGroup)}>
                          Add Link
                        </Button>
                      </Grid>
                    </Grid>
                  )}
                </FieldArray>
              </FormStepper>
            )}
          </Formik>
        </CardContent>
      </Card>
    </Container>
  );
};

export default App;

<FieldArray />— это компонент, помогающий манипулировать массивами или списками. Он получает свойство name, содержащее путь к ключу в values, содержащем нужный массив. Через свойства компонент предоставляет вам доступ к вспомогательным методам массива. В приведенном выше блоке кода методы pushи removeиспользуются для добавления и удаления элементов из linksмассива.

3 поля массива

Добавить проверки

Теперь, когда компонент формы имеет все необходимые функции, пришло время добавить проверки. Yup будет использоваться для добавления проверок. Импортируйте из yupбиблиотеки в src/App.js:

import { array, object, string } from "yup"; // new import

Компонент Formikполучает validationSchemaреквизит, который представляет собой объект, содержащий проверки для полей формы. Скопируйте и вставьте блок кода ниже и добавьте его в качестве реквизита для Formikкомпонента.

validationSchema={object({
    firstname: string().required("First Name is required"),
    lastname: string().required("Last Name is required"),
    links: array(
    object({
       linkname: string().required("Link Name is required"),
       linkurl: string().required("Link URL is required"),
       })
       ),
})}

4 Финальный проект

Вывод

Formik зарекомендовал себя как надежная, масштабируемая и высокопроизводительная библиотека реагирования для создания форм: за последний год было скачано более 2 миллионов раз . В этой статье была построена сложная форма. Formik предлагает гибкость и позволяет нам создавать настраиваемые компоненты шагового двигателя. Yup хорошо работает с Formik, также можно использовать пользовательские проверки.

Ссылка: https://blog.openreplay.com/dynamic-multi-step-forms-with-formik

#formik #реагировать #reactjs

Как справиться с проверкой HTML-формы с помощью PristineJS

Проверка формы помогает вам контролировать и дезинфицировать значения, введенные во входные данные формы в ваших приложениях; это также помогает предоставлять содержательные сообщения для неправильных значений в форме. Проверка ввода формы имеет важное значение для разработки, гарантируя, что мы получаем только необходимую информацию из формы. Есть несколько способов обработки проверки формы в веб-приложении; один из этих методов — использование PristineJS, и в этой статье мы покажем вам, как его использовать.

PristineJS — это библиотека JavaScript, которая помогает упростить проверку HTML-форм, позволяя создавать собственные проверки формы и сообщения об ошибках. Кроме того, он обеспечивает большую гибкость при обработке проверки и ошибок для вашего приложения, позволяя вам устанавливать приоритет для проверки значений формы, создавать сообщения об ошибках для ввода и т. д.

Есть несколько преимуществ использования PristineJS для проверки формы, и мы рассмотрим некоторые из них ниже:

  • Легкий и простой в интеграции: размер файла минимален, и его относительно легко добавить в ваши веб-приложения; все, что вам нужно сделать, это загрузить zip-файл и связать файл pristine.js в папке dist с вашим приложением.
  • Нулевая зависимость
  • Это позволяет вам создавать собственные глобальные проверки, легко доступные во входных данных, используя атрибуты элементов.
  • Пользовательская проверка для определенного поля.
  • Пользовательские сообщения об ошибках.
  • Обеспечение контроля над уровнем приоритета ошибки.

Проверка формы с помощью PristineJS

В этом разделе мы рассмотрим, как интегрировать PristineJS в ваше приложение и создать многофункциональную форму, которая должным образом проверена.

Чтобы добавить PristineJS в свое приложение, посетите официальный сайт и нажмите кнопку загрузки на изображении ниже.

первый

После завершения загрузки разархивируйте файл и скопируйте либо файл pristine.min.js, либо файл pristine.js из папки dist и pa.

...
        <!-- PristineJS file -->
        <script src="./src/pristine.min.js"></script>
        <!-- PristineJS file -->
        <script src="./src/app.js"></script>
    ...

По завершении у нас будет такая структура:

📦pristinejs
  ┣ 📂src
  ┃ ┣ 📜app.js
  ┃ ┣ 📜bootstrap.css
  ┃ ┣ 📜pristine.min.js
  ┃ ┗ 📜style.css
  ┗ 📜index.html

NB: вы также можете установить PristineJS в свое приложение, выполнив команду на своем терминале:

npm install pristinejs

После этого мы можем приступить к проверке форм. Чтобы проверить форму с помощью PristineJS, нам нужно вызвать новый экземпляр; экземпляр имеет три аргумента; элемент формы, который вы хотите проверить, необязательный объект конфигурации и логическое значение для проверки в реальном времени со значением по умолчанию true. Если параметр, переданный для проверки в реальном времени (третий аргумент), имеет значение false, проверки полей будут выполняться только при отправке формы; в противном случае проверка будет происходить при вводе значений в поле.

const pristine = new Pristine(formElement, config, live);

Чтобы показать вам реальный пример того, как проверять формы с помощью PristineJS с HTML-формой ниже:

...
    <div class="my-4">
        <h2>Form validation</h2>

        <form novalidate id="form1">
          <div class="mb-3">
            <label for="form1-email" class="form-label">Email address</label>
            <input
              required
              type="email"
              class="form-control"
              id="form1-email"
              placeholder="Enter your email"
            />
          </div>
          <div class="mb-3">
            <label for="form1-message" class="form-label">Message</label>
            <textarea
              required
              minlength="5"
              class="form-control"
              id="form1-message"
              rows="3"
            ></textarea>
          </div>

          <button class="btn btn-primary w-100">Submit</button>
        </form>
      </div>
...

Если вы посмотрите на блок кода выше, у нас есть атрибут novalidate в форме; это отключит проверку HTML по умолчанию. Итак, в нашем app.js мы создадим новый экземпляр Pristine и передадим элемент формы в качестве параметра; в событии отправки для формы мы вызовем метод проверки из класса Pristine, чтобы инициировать проверку формы.

const defaultConfig = {
  // class of the parent element where the error/success class is added
  classTo: "form-group",
  errorClass: "has-danger",
  successClass: "has-success",
  // class of the parent element where error text element is appended
  errorTextParent: "form-group",
  // type of element to create for the error text
  errorTextTag: "div",
  // class of the error text element
  errorTextClass: "text-help",
};
...
window.onload = function () {
  const form1 = el("form1");
  const pristine1 = new Pristine(form1);

  form1.addEventListener("submit", function (e) {
    e.preventDefault();
    const valid = pristine1.validate();

    if (valid) {
      alert("Form is valid");
    } else {
      alert("Form is invalid");
    }
  });
...
};

function el(id) {
  return document.getElementById(id);
}

Если вы посмотрите на блок кода выше, вы также заметите переменную defaultConfig; это объект со свойствами того, как PristineJS будет обрабатывать ошибки.

Встроенные валидаторы

В этом разделе мы рассмотрим некоторые встроенные валидаторы для PristineJS:

... 
<div class="my-4">
        <h2>Built in validators</h2>

        <form novalidate autocomplete="off" id="form2">
          <div class="mb-3">
            <label for="form2-age" class="form-label">Age</label>
            <input
              required
              data-pristine-type="integer"
              class="form-control"
              id="form2-age"
              placeholder="Enter your age"
            />
          </div>

          <div class="mb-3">
            <label for="form2-email" class="form-label">Email address</label>
            <input
              autocomplete="off"
              required
              data-pristine-type="email"
              class="form-control"
              id="form2-email"
              placeholder="Enter your email"
            />
          </div>

          <div class="mb-3">
            <label for="form2-email" class="form-label">Password</label>
            <input
              autocomplete="off"
              required
              type="password"
              class="form-control"
              id="form2-password"
              placeholder="Enter your password"
            />
          </div>

          <div class="mb-3">
            <label for="form2-confirmPassword" class="form-label"
              >Confirm Password</label
            >
            <input
              autocomplete="off"
              required
              type="password"
              data-pristine-equals="#form2-password"
              class="form-control"
              id="form2-confirmPassword"
              placeholder="Confirm your password"
            />
          </div>

          <button class="btn btn-primary w-100">Submit</button>
        </form>
      </div>
...

Из приведенного выше блока кода у нас есть атрибут «data-pristine-type» для первого элемента ввода; этот атрибут указывает значение, принимаемое полем ввода, с параметром в виде электронной почты, числа или целого числа; он определяет тип проверки, принимаемый полем ввода. У нас также есть атрибут валидатора data-pristine-equals; это принимает селектор значения поля для соответствия. Атрибуты проверки PristineJS имеют формат data-pristine-Validation_rule_tag.

Ниже представлена ​​таблица со встроенными валидаторами для PristineJS.

ВалидаторОпределение
исходный тип данныхЭто указывает тип данных поля; он принимает числа, целые числа или адрес электронной почты в качестве значений
нетронутые данные требуютсяЭтот валидатор указывает, что поле обязательно
нетронутые данные-maxlengthЭто позволяет указать максимальное количество символов в поле.
данные нетронутый минимальная длинаЭто позволяет указать минимальное количество символов в поле.
данные нетронутый минУказывает минимальное значение для поля
данные нетронутый максУказывает максимальное значение для поля
исходный шаблон данныхЭтот валидатор принимает шаблон регулярного выражения , который будет использоваться для проверки поля.
нетронутые данные равныПроверяет, равно ли поле полю, переданному в качестве значения атрибута. например, data-pristine-equals="#form2-password"

2 число с плавающей запятой, переданное возрасту

Пользовательская проверка

PristineJS позволяет создавать настраиваемые глобальные валидаторы, которые можно использовать в полях форм, или настраиваемые проверки, привязанные к определенному полю/элементу ввода.

...
  Pristine.addValidator(
    "name",
    function (value) {
      return value.length > 0 && value.length < 20;
    },
    "Name must be between 1 and 20 characters"
  );
...

Блок кода выше создает глобальный валидатор; мы можем добиться этого, вызвав метод addValidator для глобального класса Pristine. Метод addValidator принимает четыре параметра: имя проверки, функцию со значением поля для проверки, переданным в качестве аргумента, сообщение проверки и уровень приоритета проверки.

Чтобы создать пользовательскую проверку, привязанную к полю, вы вызовете метод addValidator из нового экземпляра класса Pristine. Метод также принимает те же параметры, что и глобальный валидатор выше, единственное различие заключается в первом параметре; вместо имени проверки проверяемый элемент является первым параметром.

...  
pristine3.addValidator(
    el("form3-age"),
    (value) => {
      return value >= 18 && value <= 65;
    },
    "Age must be between 18 and 65"
  );
...

Мы применим пользовательские валидаторы, созданные выше, которые будут применены к HTML-форме в блоке кода ниже:

<!-- CUSTOM VALIDATION -->
<div class="my-4">
  <h2>Custom validation</h2>

  <form autocomplete="off" id="form3">
    <div class="mb-3">
      <label for="form3-name" class="form-label">Name</label>
      <input
        data-pristine-required
        data-pristine-name
        class="form-control"
        id="form3-name"
        placeholder="Enter your name"
      />
    </div>

    <div class="mb-3">
      <label for="form3-age" class="form-label"
        >Age: <b id="form3-age-slot"></b
      ></label>
      <input
        data-pristine-required
        type="range"
        value="0"
        class="form-range"
        id="form3-age"
      />
    </div>

    <button class="btn btn-primary w-100">Submit</button>
  </form>
</div>
<!-- CUSTOM VALIDATION -->

Элемент ввода выше с идентификатором «form3-name» принимает глобальную проверку с именем тега в качестве атрибута data-prime-name. Кроме того, мы связали ввод возрастного диапазона с настраиваемой проверкой для конкретного элемента.

3 4 действительная пользовательская проверка

Пользовательские сообщения об ошибках

PristineJS дает вам возможность перезаписывать сообщения об ошибках по умолчанию для указанных полей с помощью атрибута data-pristine-validation_tag-message, при этом настраиваемое сообщение передается в качестве значения атрибута:

...
    <div class="form-group mb-3">
    <label for="form4-message" class="form-label">Message</label>
    <input
      class="form-control"
      data-pristine-required
      data-pristine-name
      data-pristine-required-message="First name is required"
      data-pristine-name-message="First name cannot be more than 20 characters"
      placeholder="Enter your first name"
      id="form4-firstName"
    />
  </div>
...

Мы создали специальное сообщение об ошибке в приведенном выше блоке кода для проверки исходных данных и имени исходных данных.
Чтобы правильно добавлять сообщения об ошибках, мы должны обернуть ввод в div с классом, соответствующим свойству classTo в вашем объекте конфигурации для экземпляра Pristine, на котором действует проверка.

5 сообщение об ошибке

Вывод

Я надеюсь, что эта статья помогла вам научиться правильно обрабатывать проверку формы с помощью PristineJS. Мы также рассмотрели создание пользовательских ошибок и настройку сообщений об ошибках.

Ссылка: https://blog.openreplay.com/html-form-validation-with-pristinejs

#pristinejs #html #javascript

Как создавать и создавать видео в React с помощью Remotion

React — это красивая среда Javascript, которую иногда называют библиотекой «Узнай один раз, создай что угодно». Этот случай верен, потому что знание компонентов React можно использовать для разработки всего, от SPA до MPA и всего, что между ними. То же самое касается графики и анимации.

В этой статье мы узнаем, как использовать компоненты React для сборки и создания видео с помощью Remotion . Демонстрация того, что мы будем строить, приведена ниже:

первый

Что такое ремоция?

Remotion — это набор библиотек для программного создания видео с использованием React. Remotion позволяет создавать настоящие видео MP4, написанные в React. Он использует веб-технологии, такие как CSS, SVG и WebGL, для создания увлекательной движущейся графики. Remotion также позволяет использовать такие понятия, как функции и переменные. Вы можете использовать код JavaScript для создания видео и последующего преобразования его в файл MP4 с помощью Remotion.

Remotion был создан Джонни Бургером , чтобы позволить любому человеку с минимальным пониманием React, HTML, CSS и Javascript создавать видео с помощью кода. Remotion снижает барьер в области создания видео, избавляясь от сложных инструментов и обучения, необходимых для достижения успеха в области создания видео. Remotion делает это, используя текущие инструменты разработчиков Javascript и позволяя им использовать эти инструменты и навыки для преобразования кода в анимацию и видео.

Remotion включает в себя проигрыватель под названием Remotion Player, который имитирует работу настоящего видеоредактора и может использоваться для воспроизведения и просмотра вашего видео в браузере.

Начиная

You will need to install two dependencies to use Remotion effectively: Node and FFmpeg. If you are planning on downloading or extracting your video after creation, you need FFmpeg; otherwise, you can choose not to install it. Once you install the dependencies, run the command below in your terminal to bootstrap a new Remotion app.

npm init video
# or 
yarn create video

You should see a prompt like below to choose a template for your application:

2

You can choose whichever template you want for the given list in the terminal, but for this article, I will use the blank template and explain as we go.

Once Remotion is installed, open it in the code editor of your choice, and let’s go over the created files.

3

There are three files that we see in the src folder. the index.tsx, the Video.tsx, and the Composition.tsx

  • Файл index.tsxдействует как index.jsфайл в приложении create-реагировать-приложение (CRA). Он берет компонент React и через функцию рендеринга выводит его как видео в формате mp4. Мы не будем ничего изменять в этом файле
  • Файл Video.tsxдействует как Appкомпонент в приложении React, что означает, что он служит точкой входа приложения. В этом компоненте мы будем соединять разные композиции для создания видео. Файл Video.tsx показывает нам первый компонент Remotion, файл Composition.
  • Это Composition.tsxкомпонент, который содержит и регистрирует видео, которые мы хотим визуализировать, а также стили и реквизит для видео.

Внутри Composition.tsxфайла мы видим приведенный ниже код, который показывает, что в настоящее время мы ничего не возвращаем:

export const MyComposition = () => {
  return null;
};

Внутри Video.tsxфайла мы видим блок кода ниже:



import {Composition} from 'remotion';
import {MyComposition} from './Composition';
export const RemotionVideo: React.FC = () => {
  return (
    <>
      <Composition
        id="MyComp"
        component={MyComposition}
        durationInFrames={60}
        fps={30}
        width={1280}
        height={720}
      />
    </>
  );
};
  • Используется id, когда вы хотите экспортировать видео, и мы узнаем, что он делает, в разделе экспорта видео .
  • ComponentБерет импортированный Compositionкомпонент .
  • Это durationInFramesколичество кадров, которые необходимо сгенерировать.
  • Скорость fpsкадра в секунду. Разделенное durationInFramesна fpsиспользуется для расчета длины видео.
  • Ширина widthвидео в пикселях
  • Высота heightвидео в пикселях

Когда мы бежим yarn startзапускать сервер разработки, мы видим 2-секундное видео пустого холста на localhost:3000— не очень интересное, точно!

Создание нашего видео

Чтобы начать, перейдите к Composition.tsxфайлу и добавьте код ниже:

export const MyComposition = () => {
  return (
    <div
      style={{
        width: '100%',
        height: '100%',
        backgroundColor: '#f2511b',
        color: '#fff',
        textAlign: 'center',
        alignItems: 'center',
        justifyContent: 'center',
        fontSize: '2rem',
      }}
    >
      <h1>
        My name is Isaac Okoro. A fullstack developer and technical writer for the OpenReplay blog
      </h1>

    </div>
  );
};

Приведенный выше код довольно простой, так как у нас есть divнесколько встроенных стилей и h1тег с некоторым содержимым.

Когда мы сохраним и перейдем в браузер, мы должны увидеть видео, похожее на GIF ниже:

4

Получение свойств

Мы будем использовать хук от Remotion, чтобы получить свойства нашего видео. Хук — это useVideoConfig() . Этот хук возвращает объект с информацией о контексте видео, которое мы делаем. Свойства, содержащиеся в объекте, включают ширину, высоту, количество кадров в секунду, продолжительность InFrames и т. д.

Мы будем использовать информацию, предоставленную нам useVideoConfig()хуком, для отображения свойств нашего видео.




import { useVideoConfig } from 'remotion';
export const MyComposition = () => {
  const {width, height, fps, durationInFrames} = useVideoConfig();

  return (
    <div
      style={{
        width: '100%',
        height: '100%',
        backgroundColor: '#f2511b',
        color: '#fff',
        textAlign: 'center',
        alignItems: 'center',
        justifyContent: 'center',
        fontSize: '2rem',
      }}
    >
      <h1>
        My name is Isaac Okoro. A fullstack developer and technical writer for the OpenReplay blog
      </h1>
      <h3>
      This {width} * {height}px video is {durationInFrames / fps}secs long and
      was made to showcase Remotion
      </h3> 
    </div>
  );
};

В приведенном выше блоке кода мы импортировали useVideoConfig()хук из Remotion. Далее мы получили информацию о видео от хука и отрендерили его.

Когда мы сохраним и перейдем в браузер, мы должны увидеть видео, похожее на GIF ниже:

5

Примечание : мы получаем 2 секунды как наше время, потому что мы не изменили количество durationInFramesв Video.tsxфайле. Перейдите к Video.tsxфайлу и измените число durationInFramesна 120, как показано ниже, чтобы получить 4 секунды:

durationInFrames={120}

Добавление непрозрачности

На демонстрационном GIF мы видим, что экран начинает темнеть и становится все ярче по мере продолжения видео. Мы реализуем эту функцию в этом разделе.

Для этого нам нужно знать текущий кадр видео в каждый момент времени. К счастью, Remotion дает нам хук для того, что известно как [useCurrentFrame()](https://www.remotion.dev/docs/use-current-frame)хук. Этот хук извлекает текущий кадр видео.

import { useVideoConfig, useCurrentFrame } from 'remotion';

export const MyComposition = () => {
  const {width, height, fps, durationInFrames} = useVideoConfig();
  const frame = useCurrentFrame();
  const opacity = frame / durationInFrames;
  return (
    <div
      style={{
          // Inline styles remain the same
        opacity,
      }}
    >
      // Nothing changes here
    </div>
  );
};

В приведенном выше блоке кода мы импортировали useCurrentFrame()хук и сохранили его в переменной фрейма. Затем мы создали opacityпеременную, frameпеременную, разделенную на durationInFrames. После этого мы передали непрозрачность встроенным стилям.

Сохраните файл и просмотрите результаты в браузере, которые должны выглядеть как на картинке ниже:

6 Изображение, загруженное пользователем: chrome-capture-2022-6-16.gif

Экспорт видео

При рендеринге видео используйте, чтобы заголовок idв video.tsxфайле точно совпадал с заголовком в разделе сборки ваших скриптов. Я изменил имя idна «MyVideo», а также изменил его в разделе сборки моего скрипта на «MyVideo», как показано на изображениях ниже:

7

8

Сделав это, запустите, yarn buildчтобы экспортировать видео, и вы должны увидеть изображение ниже:

9

Ссылку на видео на Github можно найти здесь , а полный код для этого туториала — здесь .

Вывод

В этой статье мы рассмотрели Remotion и некоторые его удивительные возможности. Remotion еще относительно новинка, но впереди приятные сюрпризы. Remotion также поставляется со стандартными функциями, такими как выборка данных и возможности рендеринга на стороне сервера. Вы можете ознакомиться с документацией по Remotion здесь и расширить возможности, описанные в этой статье.

Ссылка: https://blog.openreplay.com/produce-videos-in-react-with-remotion

#react #javascript

Как взаимодействовать с данными формы с помощью Next.js и Hygraph

Hygraph, ранее известная как GraphCMS, представляет собой безголовую CMS, в которой используются многие преимущества GraphQL, такие как предсказуемость, производительность, скорость разработки, стабильность и гибкость. Он также использует расширенные методы жизненного цикла Next.js для доступа к данным на клиенте и ко всем данным, отображаемым на сервере. Используя Hygraph в сочетании с Next.js, вы можете создавать PWA, магазины электронной коммерции, блоги и проекты настольных приложений.

В этом руководстве мы воспользуемся возможностями Next.js и объединим их с Hygraph, используя Next.js для создания API в нашем бэкэнде Next.js, который будет взаимодействовать со службами Hygraph. Мы сделаем HTTP-запрос в нашем приложении Next.js, который мы можем использовать для сбора комментариев, отправленных пользователями к сообщению в блоге, и просмотра их на нашей панели инструментов Hygraph. Это позволяет нам публиковать или удалять комментарии на панели управления Hygraph. После публикации он будет отображаться в разделе комментариев нашего блога.

Чтобы следовать этому руководству, вам необходимо знать JavaScript, Next.js и учетную запись Hygraph . У вас должен быть установлен node.js.

Настройка хайграфа

Чтобы создать учетную запись Hygraph, следуйте инструкциям здесь . После успешной настройки учетной записи Hygraph нажмите на стартовый шаблон блога . Мы хотим сосредоточиться на реализации формы и сборе материалов, отправленных пользователями.

первый

Как только проект будет создан, перейдите к «схеме» на панели инструментов проекта Hygraph и создайте новый файл model. Назовите modelкомментарий и добавьте следующие поля:

  • Name- Строка, однострочный текст и сделайте его required.
  • Email- Строка, однострочный текст и сделайте его required.
  • Comment- Строка, многострочный текст и сделать его required.

Прокрутите вниз Referenceи следуйте изображению ниже, чтобы определить тип ссылки, ссылку на свою публикацию, ссылку на направление и нажмите «Продолжить».

2

Вот как устроен Commentконтент.

3

Настройка нашего проекта Next.js

Давайте начнем с запуска команды ниже на нашем терминале:

yarn create next-app --example cms-graphcms cms-graphcms-app && cd cms-graphcms-app

Или, если вы используете NPM, выполните следующую команду:

npx create-next-app --example cms-graphcms cms-graphcms-app && cd cms-graphcms-app

В остальной части урока я буду использовать Yarn.

Этот проект представляет собой одностраничное приложение, загружаемое с помощью Next.js и Tailwind CSS. Только с единственной целью этого руководства команда, которую мы запускаем, представляет собой статически сгенерированный пример шаблона блога с использованием Next.js и GraphCMS. Этот метод позволяет нам сосредоточиться на настройке нашего бэкэнда и реализации раздела комментариев в нашем блоге.

Настройка ролей и разрешений

Переименуйте .env.local.exampleфайл в этом каталоге в .env.

HYGRAPH_PROJECT_API=
HYGRAPH_PROD_AUTH_TOKEN=
HYGRAPH_DEV_AUTH_TOKEN=
HYGRAPH_PREVIEW_SECRET=

Вернитесь к Хайграфу. На панели управления проекта перейдите на страницу «Настройки» > «Доступ к API» . Затем установите каждую переменную в .env:

  • HYGRAPH_PROJECT_API: установите конечную точку Content API в разделе Конечные точки в верхней части страницы.
  • HYGRAPH_PROD_AUTH_TOKEN: Скопируйте NEXT_EXAMPLE_CMS_GCMS_PROD_AUTH_TOKENтокен в разделе Постоянные токены аутентификации > Существующие токены внизу страницы. Это будет запрашивать только опубликованный контент.
  • HYGRAPH_DEV_AUTH_TOKEN: Скопируйте NEXT_EXAMPLE_CMS_GCMS_DEV_AUTH_TOKENтокен в разделе Постоянные токены аутентификации > Существующие токены внизу страницы. Это будет запрашивать только содержимое, которое находится в черновике.
  • HYGRAPH_PREVIEW_SECRETможет быть любой случайной строкой (но избегайте пробелов), например MY_SECRET- это используется для режима предварительного просмотра .

В вашем next.config.js fileзамените на images.domainприведенный ниже код.

// next.config.js
module.exports = {
  images: {
    domains: ['media.graphassets.com'],
  },
}

В корневой папке выполните следующую команду:

yarn install
yarn dev

Ваш блог должен работать по адресу http://localhost:3000 ! Вот как выглядит наш блог.

4

Запросить данные из Hygraph

Next.js позволяет нам создавать API в нашем приложении Next.js без создания отдельного сервера Node.js. Здесь мы напишем запрос, который пойдет прямо к нашему серверу Next.js. Создайте новый файл getComment.jsв libпапке и добавьте следующий код:

// lib/getComment.js

// submit user comment to GraphCMS
export const submitComment = async (obj) => {
  const result = await fetch('/api/comments',{
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(obj),
  })
  return result.json();
}

Здесь мы принимаем объекты комментариев objи делаем HTTP-запрос к нашему бэкэнду Next.js. Мы сделали запрос на выборку для нашего /api/comments. Все файлы внутри папки pages/apiсопоставляются /api/и обрабатываются как конечная точка API, а не как страница.

Создание макета формы

В папке компонентов создайте CommentsForm.jsфайл и добавьте следующий код:

// components/CommentsForm.js

import React, { useRef, useState} from 'react';
import { submitComment } from 'lib/getComment';

const CommentsForm = ({ slug }) => {
  const [error, setError] = useState(false);
  const [showSuccessMessage, setShowSuccessMessage] = useState(false);
  const commentEl = useRef();
  const nameEl = useRef();
  const emailEl = useRef();

  const handleCommentSubmission = () => {
    setError(false);

    const { value: comment } = commentEl.current;
    const { value: name } = nameEl.current;
    const { value: email } = emailEl.current;

    if(!comment || !name || !email) {
      setError(error);
      return
    }

    const commentObj = {
      name, email, comment, slug
    };

    submitComment(commentObj)
      .then((res) => {
        setShowSuccessMessage(true);
        setTimeout(() => {
          setShowSuccessMessage(false);
        }, 3000);
      })
  }
  return (
    <div className='bg-white shadow-lg rounded-lg p-8 pb-12 mb-8 lg:w-1/2 justify-center items-center my-0 mx-auto'>
      <h3 className='text-xl mb-8 font-semibold border-b pb-4'>Leave a Reply</h3>
      <div className='grid grid-cols-1 gap-4 mb-4'>
        <textarea
          ref={commentEl}
          className='p-4 outline-none w-full rounded-lg focus:ring-2 focus:ring-gray-200 bg-gray-100 text-gray-700'
          placeholder='Comment'
          name='comment'
        />
      </div>
      <div className='grid grid-cols-1 lg:grid-cols-2 gap-4 mb-4'>
        <input
          type={'text'} 
          ref={nameEl}
          className='py-2 px-4 outline-none w-full rounded-lg focus:ring-2 focus:ring-gray-200 bg-gray-100 text-gray-700'
          placeholder='Name'
          name='name'
        />
        <input
          type='email' 
          ref={emailEl}
          className='py-2 px-4 outline-none w-full rounded-lg focus:ring-2 focus:ring-gray-200 bg-gray-100 text-gray-700'
          placeholder='Email'
          name='email'
        />
      </div>
      {error && <p className='text-xs text-red-500'>All fields are required.</p>}
      <div className='mt-8'>
        <button type='button' onClick={handleCommentSubmission}
          className='transition duration-500 ease hover:bg-gray-500 inline-block bg-gray-700 text-lg rounded-full text-white py-3 px-8 cursor-pointer'
        >
          Post Comment
        </button>
        {showSuccessMessage && <span className='text-xl float-right font-semibold mt-3 text-green-500'>Comment Submitted for review</span>}
      </div>
    </div>
  )
}
export default CommentsForm;

В нашем commentForm, мы отправляем слаг каждого поста. Мы использовали [useRef](https://www.w3schools.com/react/react_useref.asp#:~:text=The%20useRef%20Hook%20allows%20you,access%20a%20DOM%20element%20directly.)хук, потому что хотим не хранить данные в состоянии, а считывать значения из поля ввода и затем отправлять их в Hygraph. Мы также использовали [useState](https://reactjs.org/docs/hooks-state.html)хук для обработки состояния при возникновении ошибки, и наши комментарии успешно отправляются в Hygraph.

В pages/[slug].jsфайле импортируйте CommentForms.jsи добавьте его в articleэлемент ниже <Postbody />и передайте в slugкачестве реквизита.

// pages/[slug].js
import CommentsForm from 'components/CommentsForm'

export default function Post({ post, morePosts, preview }) {
  /*  */
  <CommentsForm slug={post.slug} />
  /*  */
}

Вот как выглядит наша форма комментариев:

5

Создание нашего API в Nextjs для взаимодействия с Hygraph

В нашем pages/api, создайте новый файл comments.jsи добавьте код ниже:

// pages/api/comments.js

import { GraphQLClient, gql } from 'graphql-request';

const graphqlAPI = process.env.HYGRAPH_PROJECT_API;

// export a default function for API route to work
export default async function comments(req, res) {
  const graphQLClient = new GraphQLClient((graphqlAPI), {
    headers: {
      authorization: `Bearer ${process.env.HYGRAPH_DEV_AUTH_TOKEN}`,
    },
  });
  const query = gql`
    mutation CreateComment($name: String!, $email: String!, $comment: String!, $slug: String!) {
      createComment(data: {name: $name, email: $email, comment: $comment, post: {connect: {slug: $slug}}}) { id }
    }
  `;
  const result = await graphQLClient.request(query, {
    name: req.body.name,
    email: req.body.email,
    comment: req.body.comment,
    slug: req.body.slug,
  });
  return res.status(200).send(result);
}

Как вы могли заметить, мы импортируем GraphQLClientи gqlиз файлов graphql-request. Чтобы добавить эти зависимости, выполните приведенную ниже команду в своем терминале.

yarn add graphql graphql-request

GraphQLClientпозволяет нам публиковать данные в Hygraph. Мы настроили GraphQLClient, указав заголовок авторизации с HYGRAPH_DEV_AUTH_TOKENот Hygraph. Это поможет авторизовать GraphQLClient. Мы также создали запрос на мутацию, который поможет нам добавить новые данные — новые комментарии. Мы также используем его для подключения к определенному сообщению, которое пользователь прокомментировал, указав расширение slug.

Приложение в действии

Теперь перейдите к нашему сообщению в блоге и комментируйте.

6

Перейдите к Hygraph, и мы увидим наш комментарий, и он был сохранен как черновик. Так что либо публикуем, либо удаляем.

7

Отображение комментариев пользователей

В этом разделе мы рассмотрим отображение комментария пользователя для каждого конкретного сообщения после его публикации в нашем интерфейсе.

Внутри lib/getComment.jsфайла импортируйте requestи gqlиз graphql-requestи используйте их для извлечения name, commentи dateкомментариев пользователя к сообщению в блоге.

// lib/getComment.js

import { request, gql } from "graphql-request";

const graphqlAPI = "Your api key"

// getting post comments
export const getComments = async (slug) =>   {
    const query = gql`
        query GetComments($slug: String!) {
            comments(where: { post: { slug: $slug } }) {
                name
                createdAt
                comment
            }
        }
    `
    const result = await request(graphqlAPI,query, { slug });
    return result.comments;
}

В нашей componentsпапке создайте Comments.jsфайл и добавьте код ниже:

// components/Comments.js

import React, { useEffect, useState } from 'react'
import  parse  from 'html-react-parser';
import { getComments } from 'lib/getComment';

const Comments = ({ slug }) => {
  const [comments, setComments ] = useState([]);
  useEffect(() => {
      getComments(slug)
        .then((result) => setComments(result))
  }, [])
  return (
    <>
      {comments.length > 0 && (
        <div className='bg-white shadow-lg rounded-lg p-8 pb-12 mb-8'>
          <h3 className='text-xl mb-8 font-semibold border-b pb-4'>
            {comments.length}
            {''}
            Comments
          </h3>
          {comments.map((comment) => (
            <div key={comment.createdAt} className='border-b border-gray-100 mb-4 pb-4'>
              <p className='mb-4'>
                <span className='font-semibold'>{comment.name}</span>
                {''}
                on
                {''}
                {new Date(comment.createdAt).toLocaleDateString(undefined, {
                      day:   'numeric',
                      month: 'short',
                      year:  'numeric',
                  })}
              </p>
              <p className='whitespace-pre-line text-gray-600 w-full'>{parse(comment.comment)}</p>
            </div>
          ))}
        </div>
      )}
    </>
  )
}
export default Comments;

Раньше мы useEffectполучали только что добавленные комментарии. Установите html-react-parser, выполнив команду ниже:

yarn add html-react-parser

В pages/[slug].jsфайле импортируйте Comment.jsи добавьте его в articleэлемент ниже <CommentsForm />и передайте slugкак реквизит.

// pages/[slug].js

import Comments from 'components/Comments'

export default function Post({ post, morePosts, preview }) {
  /*   */
  <Comments slug={post.slug} />
  /*   */
}

Вот как выглядит наша форма комментариев:

8

Вывод

В этой статье мы продемонстрировали, как реализовать раздел комментариев с помощью Next.js. Мы рассмотрели, как создать API в нашем бэкэнде Next.js, который будет взаимодействовать с Hygraph. Мы также рассмотрели, как настроить Hygraph, а также отправлять и получать данные с помощью Next.js и GraphQL из Hygraph.

Hygraph — одна из лучших систем управления контентом GraphQL. Hygraph — отличный инструмент, обеспечивающий бесшовную интеграцию с любым приложением.

Ссылка: https://blog.openreplay.com/interacting-with-form-data-using-next-js-and-hygraph

#hygraph #nextjs #reatcjs

Как загружать изображения с помощью Dropzone с помощью Laravel 9

Dropzone — самая известная бесплатная библиотека с открытым исходным кодом, которая обеспечивает загрузку файлов перетаскиванием с предварительным просмотром изображений . В этом примере я буду использовать Laravel , но вы можете использовать предыдущие версии.

Загрузка изображения Laravel Dropzone

  1. Сначала загрузите несколько изображений с помощью dropzone.
  2. Сохранение изображений с разными именами файлов в базу данных.
  3. Удаление изображений прямо из окна предварительного просмотра dropzone.

Шаг 1: Загрузите проект Laravel

Создайте проект Laravel, введя следующую команду.

composer create-project --prefer-dist laravel/laravel dropzonefileupload

Шаг 2: Настройте базу данных MySQL

Настройте базу данных в файле .env  .

//.env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=dropzonefileupload
DB_USERNAME=root
DB_PASSWORD=

Я настроил учетные данные для локальной базы данных.

Шаг 3: Создайте модель и файл миграции

Введите следующую команду в свой cmd.

$ php artisan make:model ImageUpload -m

Он создаст два файла.

  1. Модель ImageUpload.php .
  2. файл миграции create__image_uploads_table .

Нам нужно создать схему для таблицы загрузки изображений. Итак, перейдите в  Laravel >> база данных >> миграции >> create__image_uploads_table.

//create_image_uploads_table

 public function up()
    {
        Schema::create('image_uploads', function (Blueprint $table) {
            $table->increments('id');
            $table->text('filename');
            $table->timestamps();
        });
    }

Шаг 4: Создайте файл представления

Создайте файл в resources >> views >> imageupload.blade.php и поместите в него следующий код В этом файле мы добавим dropzone для загрузки файлов.

<!-- imageupload.blade.php -->
<!DOCTYPE html>
<html>
<head>
    <title>Laravel Multiple Images Upload Using Dropzone</title>
    <meta name="_token" content="{{csrf_token()}}" />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.4.0/min/dropzone.min.css">
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.4.0/dropzone.js"></script>
</head>
<body>
<div class="container">
       
    <h3 class="jumbotron">Laravel Multiple Images Upload Using Dropzone</h3>
    <form method="post" action="{{url('image/upload/store')}}" enctype="multipart/form-data" 
                  class="dropzone" id="dropzone">
    @csrf
</form>   
</body>
</html>

В этот файл мы сначала добавляем наши bootstrap.min.css, dropzone.min.css. Затем мы добавляем jquery.js и dropzone.js. Далее мы создаем форму и присоединяем к ней класс dropzone.

Кроме того, у нас есть некоторый текст, отображаемый в нашем поле загрузки. Кроме того, если это изображение успешно загружено, на нем будет отображаться галочка, если только оно не будет отображать крестик и ошибку.

Шаг 5: Настройте Dropzone

Теперь пишем все конфигурации для Dropzone. Поэтому добавьте следующий код в файл представления.

<!-- imageupload.blade.php -->
<!DOCTYPE html>
<html>
<head>
    <title>Laravel Multiple Images Upload Using Dropzone</title>
    <meta name="_token" content="{{csrf_token()}}" />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.4.0/min/dropzone.min.css">
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.4.0/dropzone.js"></script>
</head>
<body>
<div class="container">
       
    <h3 class="jumbotron">Laravel Multiple Images Upload Using Dropzone</h3>
    <form method="post" action="{{url('image/upload/store')}}" enctype="multipart/form-data" 
                  class="dropzone" id="dropzone">
    @csrf
</form>   
<script type="text/javascript">
        Dropzone.options.dropzone =
         {
            maxFilesize: 12,
            renameFile: function(file) {
                var dt = new Date();
                var time = dt.getTime();
               return time+file.name;
            },
            acceptedFiles: ".jpeg,.jpg,.png,.gif",
            addRemoveLinks: true,
            timeout: 5000,
            success: function(file, response) 
            {
                console.log(response);
            },
            error: function(file, response)
            {
               return false;
            }
};
</script>
</body>
</html>

В файле выше мы добавляем параметры конфигурации для Dropzone. Вы можете найти любой из вариантов конфигурации, доступных в  документации dropzone .

Теперь пройдемся по каждому варианту.

  1. maxFilesize установлен на 12. Dropzone разрешает только изображения размером менее 12 МБ. Вы можете сделать его меньше или больше в зависимости от ваших требований.
  2. Функция renameFile  вызывается перед загрузкой файла на сервер и переименовывает файл.

acceptFiles проверяет MIME-тип или расширение файла по этому списку Определяем  .jpeg, .jpg, .png, .gif. Вы можете изменить в зависимости от ваших потребностей.

  1. addRemoveLinks имеет значение true. Dropzone отобразит кнопку «Удалить», чтобы удалить загруженный файл.
  2. таймаут установлен на 5000

Шаг 6: Создайте один контроллер и маршрут 

php artisan make:controller ImageUploadController

Он создаст файл с именем ImageUploadController.php ; прописываем маршруты в файле route >> web.php  . Итак, давайте сделаем это.

//web.php

Route::get('image/upload','ImageUploadController@fileCreate');
Route::post('image/upload/store','ImageUploadController@fileStore');
Route::post('image/delete','ImageUploadController@fileDestroy');

Следующим шагом будет переход к файлу ImageUploadController.php  и добавление некоторого кода в функцию fileCreate() .

// ImageUploadController.php

public function fileCreate()
    {
        return view('imageupload');

    }

В методе create() мы просто возвращаем созданное нами загруженное изображение .

пример загрузки файла laravel dropzone

Шаг 7: Сохраните файл в базу данных

Нам нужно закодировать функцию fileStore() последовательно, чтобы сохранить имя файла в базе данных.

// ImageUploadController.php

use App\ImageUpload;

public function fileStore(Request $request)
    {
        $image = $request->file('file');
        $imageName = $image->getClientOriginalName();
        $image->move(public_path('images'),$imageName);
        
        $imageUpload = new ImageUpload();
        $imageUpload->filename = $imageName;
        $imageUpload->save();
        return response()->json(['success'=>$imageName]);
    }

Загрузка нескольких изображений Laravel с помощью перетаскивания с использованием примера dropzone.js

Шаг 8: Удалить файл из базы данных

Теперь мы добавляем функцию removeFile() в конфигурацию dropzone.

<!-- imageupload.blade.php -->
<!DOCTYPE html>
<html>
<head>
    <title>Laravel Multiple Images Upload Using Dropzone</title>
    <meta name="_token" content="{{csrf_token()}}" />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.4.0/min/dropzone.min.css">
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.4.0/dropzone.js"></script>
</head>
<body>
<div class="container">
       
    <h3 class="jumbotron">Laravel Multiple Images Upload Using Dropzone</h3>
    <form method="post" action="{{url('image/upload/store')}}" enctype="multipart/form-data" 
                  class="dropzone" id="dropzone">
    @csrf
</form>   
<script type="text/javascript">
        Dropzone.options.dropzone =
         {
            maxFilesize: 12,
            renameFile: function(file) {
                var dt = new Date();
                var time = dt.getTime();
               return time+file.name;
            },
            acceptedFiles: ".jpeg,.jpg,.png,.gif",
            addRemoveLinks: true,
            timeout: 50000,
            removedfile: function(file) 
            {
                var name = file.upload.filename;
                $.ajax({
                    headers: {
                                'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content')
                            },
                    type: 'POST',
                    url: '{{ url("image/delete") }}',
                    data: {filename: name},
                    success: function (data){
                        console.log("File has been successfully removed!!");
                    },
                    error: function(e) {
                        console.log(e);
                    }});
                    var fileRef;
                    return (fileRef = file.previewElement) != null ? 
                    fileRef.parentNode.removeChild(file.previewElement) : void 0;
            },
       
            success: function(file, response) 
            {
                console.log(response);
            },
            error: function(file, response)
            {
               return false;
            }
};
</script>
</body>
</html>

Добавьте функцию fileDestroy() для удаления файла из базы данных. Добавьте следующий код в FileUploadController.

//ImageUploadController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\ImageUpload;

class ImageUploadController extends Controller
{
    public function fileCreate()
    {
        return view('imageupload');
    }
    public function fileStore(Request $request)
    {
        $image = $request->file('file');
        $imageName = $image->getClientOriginalName();
        $image->move(public_path('images'),$imageName);
        
        $imageUpload = new ImageUpload();
        $imageUpload->filename = $imageName;
        $imageUpload->save();
        return response()->json(['success'=>$imageName]);
    }
    public function fileDestroy(Request $request)
    {
        $filename =  $request->get('filename');
        ImageUpload::where('filename',$filename)->delete();
        $path=public_path().'/images/'.$filename;
        if (file_exists($path)) {
            unlink($path);
        }
        return $filename;  
    }
}

Наконец, наша загрузка образа Laravel Dropzone  завершена. Спасибо, что взяли.

Ссылка: https://appdividend.com/2022/02/28/laravel-dropzone-image-upload/

#laravel #php