Bonne journée, mes amis!
Dans ce petit tutoriel, je veux vous montrer un exemple de validation de formulaire client-serveur.
Le client sera implémenté dans React, le serveur dans Express.
Nous ne réinventerons pas la roue, mais utiliserons des solutions toutes faites: react-hook-form sera utilisé pour valider le formulaire côté client (+: les hooks sont utilisés, russe), et côté serveur - express-validator . Les composants stylisés (CSS-in-JS ou All-in-JS, étant donné JSX)
seront utilisés pour le style . Le code source de l'exemple est ici .
Vous pouvez jouer avec le code ici .
Sans autre préambule.
Client
Créez un projet à l'aide de create-react-app :
yarn create react-app form-validation # npm init react-app form-validation # npx create-react-app form-validation
À l'avenir, j'utiliserai yarn pour installer les dépendances et exécuter des commandes.
Structure du projet après avoir supprimé les fichiers inutiles:
public index.html src App.js index.js styles.js server.js ...
Installer les dépendances:
# yarn add styled-components react-hook-form # ( ) yarn add express express-validator cors # ( ) yarn add -D nodemon # yarn add concurrently
Étant donné que les composants stylisés ne peuvent pas importer de polices, nous devrons les ajouter à public / index.html:
<head>
...
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
href="https://fonts.googleapis.com/css2?family=Comfortaa&display=swap"
rel="stylesheet"
/>
</head>
Notre formulaire aura trois champs: un nom d'utilisateur, leur adresse e-mail et un mot de passe. Conditions auxquelles les données doivent satisfaire:
- Nom
- de 2 à 10 caractères
- cyrillique
- Email
- aucune exigence particulière
- Mot de passe
- 8 à 12 caractères
- Latin: lettres dans tous les cas, chiffres, trait de soulignement et tiret
Commençons par le style (src / styles.js; pour la coloration syntaxique, j'utilise l'extension VSCode 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
}
Importons et incluons des styles globaux dans src / index.js:
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')
)
Accédez au fichier client principal (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 />
</>
)
}
La méthode register () du hook useForm () prend en charge tous les attributs de la balise d'entrée. Une liste complète de ces attributs . Dans le cas d'un nom, nous pourrions nous limiter à une expression régulière.
Démarrez le serveur pour le client à l'aide de yarn start et testez le formulaire:
Excellent. La validation côté client fonctionne comme prévu. Mais vous pouvez toujours le désactiver. Par conséquent, une validation sur le serveur est nécessaire.
Serveur
Commençons par implémenter le serveur (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}`)
})
Une liste complète des validateurs disponibles peut être trouvée ici .
Ajoutons quelques scripts à package.json - "server" pour démarrer le serveur et "dev" pour démarrer les serveurs simultanément:
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"server": "nodemon server",
"dev": "concurrently \"yarn server\" \"yarn start\""
}
Exécuter le développement de fils et tester la soumission du formulaire:
Excellent. Il semble que nous ayons réussi.
Nous avons couvert une validation de formulaire client-serveur très simple. Dans le même temps, des options plus complexes n'impliquent qu'une augmentation du nombre de validateurs, les principes généraux restent les mêmes. Il est également intéressant de noter que la validation de formulaire côté client peut être facilement implémentée en utilisant HTML ( GitHub , CodeSandbox ).
Merci pour votre attention et bonne journée.