Пошаговые формы позволяют разбить ввод данных на отдельные этапы. Рассмотрим, как сделать подобную форму. Допустим, пользователь вводит сначала имя, потом 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> ); }
Визуально это будет выглядеть следующим образом. Сначала отображается форма для ввода имени:
Далее по нажатию на кнопку происходит переход к форме ввода email:
И в конце отображается форма ввода пароля с кнопкой отправки, по нажатию на которую отображается окно с введенными данными: