Создание пошаговой формы

Последнее обновление: 01.04.2022

Пошаговые формы позволяют разбить ввод данных на отдельные этапы. Рассмотрим, как сделать подобную форму. Допустим, пользователь вводит сначала имя, потом email-адрес и в конце пароль. И при этом пользователю последовательно отображаются форма ввода имени, затем форма ввода email и форма ввода пароля.

Для решения этой задачи определим следующую html-страницу:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8" />
	<title>METANIT.COM</title>
</head>
<body>
	<div id="app"></div>
		  
	<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
	<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
	<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
		  
	<script type="text/babel">
		class UserForm extends React.Component {
		  constructor(props) {
			super(props)
			this.state = {
			  currentStep: 1,
			  username: "",
			  email:  "",
			  password: "", 
			}
		  }

		  handleChange = event => {
			const {name, value} = event.target
			this.setState({
			  [name]: value
			})    
		  }
		   
		  handleSubmit = event => {
			event.preventDefault()
			const { email, username, password } = this.state;
			alert(`Введенные данные: \nИмя: ${username} \nEmail: ${email} \nПароль: ${password}`)
		  }
		  
		  _next = () => {
			let currentStep = this.state.currentStep
			currentStep = currentStep >= 2? 3: currentStep + 1
			this.setState({
			  currentStep: currentStep
			})
		  }
			
		  _prev = () => {
			let currentStep = this.state.currentStep
			currentStep = currentStep <= 1? 1: currentStep - 1
			this.setState({
			  currentStep: currentStep
			})
		  }

		previousButton() {
		  let currentStep = this.state.currentStep;
		  if(currentStep !==1){
			return (
			  <button type="button" onClick={this._prev}>Назад</button>
			)
		  }
		  return null;
		}

		nextButton(){
		  let currentStep = this.state.currentStep;
		  if(currentStep <3){
			return (
			  <button type="button" onClick={this._next}>Вперед</button>        
			)
		  }
		  return null;
		}
		
		sendButton(){
		  let currentStep = this.state.currentStep;
		  if(currentStep === 3){
			return (
				<button>Отправить</button>      
			)
		  }
		  return null;
		}
	  
	  render() {    
		return (
		  <div>
		  <h1>Форма входа</h1>
		  <p>Шаг {this.state.currentStep} </p> 

		  <form onSubmit={this.handleSubmit}>
			<UserNameStep
			  currentStep={this.state.currentStep} 
			  handleChange={this.handleChange}
			  username={this.state.username}
			/>
			<EmailStep
			  currentStep={this.state.currentStep} 
			  handleChange={this.handleChange}
			  email={this.state.email}
			/>
			<PasswordStep 
			  currentStep={this.state.currentStep} 
			  handleChange={this.handleChange}
			  password={this.state.password}
			/>
			<p>
			{this.previousButton()}
			{this.nextButton()}
			{this.sendButton()}
			</p>
		  </form>
		  </div>
		);
	  }
	}

	class UserNameStep extends React.Component {
	
		render() {
		  if (this.props.currentStep !== 1) {
			return null
		  } 
		  return(
			<div>
			  <label>Имя</label>
			  <input 
				name="username"
				type="text"
				placeholder="Введите имя"
				value={this.props.username}
				onChange={this.props.handleChange}
				/>
			</div>
		  );
		}
	}
	class EmailStep extends React.Component {
		render() {
			if (this.props.currentStep !== 2) {
				return null;
			} 
			return(
				<div>
				  <label>Email</label>
				  <input
					name="email"
					type="text"
					placeholder="Введите email"
					value={this.props.email}
					onChange={this.props.handleChange}
					/>
				</div>
			);
		}
	}


	class PasswordStep extends React.Component {
		render() {
		  if (this.props.currentStep !== 3) {
			return null
		  } 
		  return(
			<div>
			  <label>Пароль</label>
			  <input
				name="password"
				type="password"
				placeholder="Введите пароль"
				value={this.props.password}
				onChange={this.props.handleChange}
				/>      
			</div>
		  );
		}
	}

	ReactDOM.createRoot(
        document.getElementById("app")
    )
    .render(<UserForm />);
	</script>
</body>
</html>

Рассмотрим, что тут опеделено. Прежде всего, отдельные этапы выделены в отдельные компоненты. Например, компонент для ввода имени:

class UserNameStep extends React.Component {
	
		render() {
		  if (this.props.currentStep !== 1) {
			return null
		  } 
		  return(
			<div>
			  <label>Имя</label>
			  <input 
				name="username"
				type="text"
				placeholder="Введите имя"
				value={this.props.username}
				onChange={this.props.handleChange}
				/>
			</div>
		  );
		}
	}

Каждый компонент-этап получает через props номер текущего этапа (this.props.currentStep), отображаемое значение (в случае с UserNameStep это this.props.username) и функцию обработчика события ввода this.props.handleChange. Все эти данные будут передаваться из главного компонента.

Главный компонент UserForm будет хранить в state все вводимые данные:

class UserForm extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			currentStep: 1,
			username: "",
			email:  "",
			password: "", 
		}
	}

С помощью свойства currentStep будет отслеживаться текущий этап. По умолчанию это первый этап.

Для обработки ввода определен один общий обработчик, поскольку в данному случае ввод для всех трех компонентов выглядит однотипным:

handleChange = event => {
			const {name, value} = event.target
			this.setState({
			  [name]: value
			})    
		  }

Через name получаем название поля ввода (атрибут name). И тут важно, что оно соответствует названию свойства из state, для ввода которого оно используется. Поэтому мы сможем использовать выражение [name]: value для установки свойства в state.

Тем не менее мы могли бы также определить отдельные обработчики для каждого поля, особенно на том случай, когда для каждого поля потребовалась какая-то своя изощренная валидация.

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

handleSubmit = event => {
	event.preventDefault()
	const { email, username, password } = this.state;
	alert(`Введенные данные: \nИмя: ${username} \nEmail: ${email} \nПароль: ${password}`)
}

Здесь просто выводим введенные данные в окне сообщения.

Кроме того, для перехода по шагам вперед-назад определены две дополнительные функции:

_next = () => {
	let currentStep = this.state.currentStep
	currentStep = currentStep >= 2? 3: currentStep + 1
	this.setState({
		currentStep: currentStep
	})
}		
_prev = () => {
	let currentStep = this.state.currentStep
	currentStep = currentStep <= 1? 1: currentStep - 1
	this.setState({
		currentStep: currentStep
	})
}

В данном случае просто переключаем текущий шаг, учитывая, что у нас всего 3 этапа.

Для управления перехода по шагам определены три дополнительные функции, которые в зависимости от текущего шага возвращают кнопки:

previousButton() {
	let currentStep = this.state.currentStep;
	if(currentStep !==1){
		return (
			<button type="button" onClick={this._prev}>Назад</button>
		)
	}
	return null;
}
nextButton(){
	let currentStep = this.state.currentStep;
	if(currentStep <3){
		return (
			<button type="button" onClick={this._next}>Вперед</button>        
		)
	}
	return null;
}
sendButton(){
	let currentStep = this.state.currentStep;
	if(currentStep === 3){
		return (
			<button>Отправить</button>      
		)
	}
	return null;
}

И в конце в функции render() главного компонента все это выводится на html-страницу:

render() {    
	return (
		<div>
		<h1>Форма входа</h1>
		<p>Шаг {this.state.currentStep} </p> 

		<form onSubmit={this.handleSubmit}>
		<UserNameStep
			  currentStep={this.state.currentStep} 
			  handleChange={this.handleChange}
			  username={this.state.username}
		/>
		<EmailStep
			  currentStep={this.state.currentStep} 
			  handleChange={this.handleChange}
			  email={this.state.email}
		/>
		<PasswordStep 
			  currentStep={this.state.currentStep} 
			  handleChange={this.handleChange}
			  password={this.state.password}
		/>
		<p>
			{this.previousButton()}
			{this.nextButton()}
			{this.sendButton()}
			</p>
		</form>
		</div>
	);
}

Визуально это будет выглядеть следующим образом. Сначала отображается форма для ввода имени:

Multistep from in React

Далее по нажатию на кнопку происходит переход к форме ввода email:

Пошаговая форма ввода в React

И в конце отображается форма ввода пароля с кнопкой отправки, по нажатию на которую отображается окно с введенными данными:

Этапы ввода на форме в React
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850