Guten Tag, Freunde!
In diesem kleinen Tutorial möchte ich Ihnen ein Beispiel für die Validierung von Client-Server-Formularen zeigen.
Der Client wird in React implementiert, der Server in Express.
Wir werden das Rad nicht neu erfinden, sondern vorgefertigte Lösungen verwenden: React-Hook-Form wird verwendet, um das Formular auf der Client-Seite (+: Hooks werden verwendet, Russisch) und auf der Serverseite zu validieren - Express-Validator .
Für das Styling werden gestaltete Komponenten (CSS-in-JS oder All-in-JS bei JSX) verwendet .
Der Quellcode für das Beispiel ist hier .
Sie können mit dem Code spielen hier .
Ohne weitere Präambel.
Kunde
Erstellen Sie ein Projekt mit der Create -React-App :
yarn create react-app form-validation # npm init react-app form-validation # npx create-react-app form-validation
In Zukunft werde ich Garn verwenden, um Abhängigkeiten zu installieren und Befehle auszuführen.
Projektstruktur nach dem Entfernen unnötiger Dateien:
public index.html src App.js index.js styles.js server.js ...
Abhängigkeiten installieren:
# yarn add styled-components react-hook-form # ( ) yarn add express express-validator cors # ( ) yarn add -D nodemon # yarn add concurrently
Da gestaltete Komponenten keine Schriftarten importieren können, müssen wir sie zu public / index.html hinzufügen:
<head>
...
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
href="https://fonts.googleapis.com/css2?family=Comfortaa&display=swap"
rel="stylesheet"
/>
</head>
Unser Formular enthält drei Felder: einen Benutzernamen, seine E-Mail-Adresse und ein Passwort. Bedingungen, die Daten erfüllen müssen:
- Name
- 2 bis 10 Zeichen
- kyrillisch
- Email
- Keine besonderen Anforderungen
- Passwort
- 8-12 Zeichen
- Lateinisch: Buchstaben auf jeden Fall, Zahlen, Unterstrich und Bindestrich
Beginnen wir mit dem Styling (src / styles.js; zur Hervorhebung der Syntax verwende ich die VSCode-Erweiterung vscode-styled-components):
//
import styled, { createGlobalStyle } from 'styled-components'
//
const GlobalStyle = createGlobalStyle`
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
background-color: #1c1c1c;
font-family: 'Comfortaa', cursive;
font-size: 14px;
letter-spacing: 1px;
color: #f0f0f0;
}
`
//
const StyledTitle = styled.h1`
margin: 1em;
color: orange;
`
//
const StyledForm = styled.form`
margin: 0 auto;
width: 320px;
font-size: 1.2em;
text-align: center;
`
//
const Label = styled.label`
margin: 0.5em;
display: grid;
grid-template-columns: 1fr 2fr;
align-items: center;
text-align: left;
`
//
const BaseInput = styled.input`
padding: 0.5em 0.75em;
font-family: inherit;
font-size: 0.9em;
letter-spacing: 1px;
outline: none;
border: none;
border-radius: 4px;
`
//
const RegularInput = styled(BaseInput)`
background-color: #f0f0f0;
box-shadow: inset 0 0 2px orange;
&:focus {
background-color: #1c1c1c;
color: #f0f0f0;
box-shadow: inset 0 0 4px yellow;
}
`
//
const SubmitInput = styled(BaseInput)`
margin: 1em 0.5em;
background-image: linear-gradient(yellow, orange);
cursor: pointer;
&:active {
box-shadow: inset 0 1px 3px #1c1c1c;
}
`
//
const BaseText = styled.p`
font-size: 1.1em;
text-align: center;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);
`
//
const ErrorText = styled(BaseText)`
font-size: ${(props) => (props.small ? '0.8em' : '1.1em')};
color: red;
`
//
const SuccessText = styled(BaseText)`
color: green;
`
//
export {
GlobalStyle,
StyledTitle,
StyledForm,
Label,
RegularInput,
SubmitInput,
ErrorText,
SuccessText
}
Importieren wir globale Stile und fügen sie in src / index.js ein:
import React from 'react'
import ReactDOM from 'react-dom'
//
import { GlobalStyle } from './styles'
import App from './App'
ReactDOM.render(
<React.StrictMode>
{/* */}
<GlobalStyle />
<App />
</React.StrictMode>,
document.getElementById('root')
)
Wechseln Sie zur Hauptclientdatei (src / App.js):
import { useState } from 'react'
//
import { useForm } from 'react-hook-form'
//
import {
StyledTitle,
StyledForm,
Label,
RegularInput,
SubmitInput,
ErrorText,
SuccessText
} from './styles'
//
function Title() {
return <StyledTitle> </StyledTitle>
}
//
function Form() {
//
const [result, setResult] = useState({
message: '',
success: false
})
// :
//
//
const { register, errors, handleSubmit } = useForm()
//
const validators = {
required: ' '
}
//
async function onSubmit(values) {
console.log(values)
const response = await fetch('http://localhost:5000/server', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(values)
})
const result = await response.json()
//
setResult({
message: result,
success: response.ok
})
}
//
function onClick() {
window.location.reload()
}
return (
<>
<StyledForm onSubmit={handleSubmit(onSubmit)}>
<Label>
:
<RegularInput
type='text'
name='name'
//
//
ref={register({
...validators,
minLength: {
value: 2,
message: ' '
},
maxLength: {
value: 10,
message: ' '
},
pattern: {
value: /[-]{2,10}/i,
message: ' '
}
})}
defaultValue=''
/>
</Label>
{/* */}
<ErrorText small>{errors.name && errors.name.message}</ErrorText>
<Label>
Email:
<RegularInput
type='email'
name='email'
ref={register({
...validators,
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: ' '
}
})}
defaultValue='email@example.com'
/>
</Label>
<ErrorText small>{errors.email && errors.email.message}</ErrorText>
<Label>
:
<RegularInput
type='password'
name='password'
ref={register({
...validators,
pattern: {
value: /^[A-Z0-9_-]{8,12}$/i,
message:
' 8 12 : , , '
}
})}
defaultValue='password'
/>
</Label>
<ErrorText small>
{errors.password && errors.password.message}
</ErrorText>
<SubmitInput type='submit' defaultValue='' />
{/* "as", "" */}
<SubmitInput as='button' onClick={onClick}>
</SubmitInput>
</StyledForm>
{/* */}
{result.success ? (
<SuccessText>{result.message}</SuccessText>
) : (
<ErrorText>{result.message}</ErrorText>
)}
</>
)
}
export default function App() {
return (
<>
<Title />
<Form />
</>
)
}
Die register () -Methode des useForm () -Hooks unterstützt alle Attribute des Eingabe-Tags. Eine vollständige Liste solcher Attribute . Im Falle eines Namens könnten wir uns auf einen regulären Ausdruck beschränken.
Starten Sie den Server für den Client mit Garnstart und testen Sie das Formular:
Großartig. Die clientseitige Validierung funktioniert wie erwartet. Sie können es aber jederzeit ausschalten. Daher ist eine Validierung auf dem Server erforderlich.
Server
Beginnen wir mit der Implementierung des Servers (server.js):
const express = require('express')
// body
// validationResult -
const { body, validationResult } = require('express-validator')
const cors = require('cors')
const app = express()
const PORT = process.env.PORT || 5000
app.use(cors())
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
//
const validators = [
body('name').trim().notEmpty().isAlpha('ru-RU').escape(),
body('email').normalizeEmail().isEmail(),
//
body('password').custom((value) => {
const regex = /^[A-Z0-9_-]{8,12}$/i
if (!regex.test(value)) throw new Error(' ')
return true
})
]
// middleware
app.post('/server', validators, (req, res) => {
//
const { errors } = validationResult(req)
console.log(errors)
//
if (errors.length) {
res.status(400).json(' ')
} else {
res.status(201).json(' ')
}
})
app.listen(PORT, () => {
console.log(` . : ${PORT}`)
})
Eine vollständige Liste der verfügbaren Validatoren finden Sie hier .
Fügen wir package.json ein paar Skripte hinzu - "Server" zum Starten des Servers und "dev" zum gleichzeitigen Starten der Server:
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"server": "nodemon server",
"dev": "concurrently \"yarn server\" \"yarn start\""
}
Garnentwicklung ausführen und Formularübermittlung testen:
Großartig. Es scheint, wir haben es geschafft.
Wir haben eine sehr einfache Validierung des Client-Server-Formulars behandelt. Gleichzeitig führen komplexere Optionen nur zu einer Erhöhung der Anzahl der Validatoren, die allgemeinen Grundsätze bleiben gleich. Es ist auch erwähnenswert, dass die clientseitige Formularvalidierung einfach mit HTML ( GitHub , CodeSandbox ) implementiert werden kann .
Vielen Dank für Ihre Aufmerksamkeit und einen schönen Tag.