От автора: компоненты являются строительными блоками приложений React. Практически невозможно создать приложение React и не использовать компоненты. Это распространено до такой степени, что некоторые сторонние пакеты предоставляют компоненты, которые вы можете использовать для интеграции функционала в свое приложение.
Эти сторонние компоненты, как правило, могут быть использованы повторно. Разница между ними и компонентами, которые, вероятно, есть в в вашем приложении, связана со спецификой.
Вот что я имею в виду. Скажем, вы управляете компанией, которая продает рубашки поло. Вы можете сделать две вещи:
Вы можете создавать поло, которые уже имеют дизайн, или
Вы можете попросить покупателя выбрать дизайн, который им нравится.
Некоторые основные вещи будут неизменными, такие как то, что поло имеет коротки рукава. Но пользователь может выбрать варианты поло, такие как цвет и размер. Поло с коротким рукавом в этом случае станет хорошим компонентом React: это один и тот же предмет с разными вариациями.
Теперь предположим, что вы работаете над формой входа. Как и рубашки поло, форма имеет неизменные характеристики, но вместо размеров и цветовых вариаций мы будем рассматривать поля ввода, кнопку отправки, возможно, даже ссылку для восстановления пароля. Это может быть скомпоновано и реализовано с изменениями в полях ввода, кнопках, ссылках и т. д.
Пример элемента ввода
Давайте посмотрим на это с точки зрения создания поля ввода для формы. Вот как будет выглядеть стандартное поле ввода текста, как компонент React:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Form extends React.Component { this.state = { username: '' } handleChange = (event) => { this.setSate({ username: event.target.value }) } render() { return ( <input name="username" type={type} placeholder="Enter username" onChange={this.handleChange} value={this.state.username} /> ) } } |
Чтобы сделать этот элемент ввода повторно используемым в других местах и проектах, нам нужно будет извлечь его в отдельный компонент. Давайте назовем его FormInput.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
const FormInput = ({ name, type, placeholder, onChange, className, value, error, children, label, ...props }) => { return ( <React.Fragment> <label htmlFor={name}>{label}</label> <input id={name} name={name} type={type} placeholder={placeholder} onChange={onChange} value={value} className={className} style={error && {border: 'solid 1px red'}} /> { error && <p>{ error }</p>} </React.Fragment> ) } FormInput.defaultProps = { type: "text", className: "" } FormInput.propTypes = { name: PropTypes.string.isRequired, type: PropTypes.string, placeholder: PropTypes.string.isRequired, type: PropTypes.oneOf(['text', 'number', 'password']), className: PropTypes.string, value: PropTypes.any, onChange: PropTypes.func.isRequired } |
Компонент принимает определенные свойства, такие как атрибуты, которые нам нужны для ввода с допустимой разметкой, включая заполнитель, значение и имя. Мы устанавливаем элемент input в функции рендеринга, устанавливая значения атрибутов в качестве свойств, которые передаются компоненту. Мы даже привязываем элемент к метке, чтобы они всегда были вместе. Идея состоит в том, чтобы компонент мог использоваться в максимально возможном количестве сценариев.
Это создает хороший компонент, потому что он обеспечивает хорошую разметку (то, что Брэд Фрост называет прямолинейным React), что показывает, что не каждый компонент должен быть какой-то очень сложной частью функционала. С другой стороны, если мы говорим о чем-то сверхосновном, скажем, о статическом заголовке, то поиск компонента React может оказаться излишним. Возможный критерий для определения того, стоит ли создавать для чего-то повторно используемый компонент, должен заключаться в том, нужны ли вам те же функции в других частях приложения. Как правило, если этот компонент используется только один раз, необходимости в «повторно используемом» компоненте нет.
Мы можем использовать наш компонент поля ввода в другом компоненте, для LoginPage.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
class LoginPage extends React.Component { state = { user: { username: "", password: "" }, errors: {}, submitted: false }; handleChange = event => { const { user } = this.state; user[event.target.name] = event.target.value; this.setState({ user }); }; onSubmit = () => { const { user: { username, password } } = this.state; let err = {}; if (!username) { err.username = "Enter your username!"; } if (password.length < 8) { err.password = "Password must be at least 8 characters!"; } this.setState({ errors: err }, () => { if (Object.getOwnPropertyNames(this.state.errors).length === 0) { this.setState({ submitted: true }); } }); }; render() { const { submitted, errors, user: { username, password } } = this.state; return ( <React.Fragment> {submitted ? ( <p>Welcome onboard, {username}!</p> ) : ( <React.Fragment> <h3>Login!</h3> <FormInput label="Username" name="username" type="text" value={username} onChange={this.handleChange} placeholder="Enter username..." error={errors.username} required className="input" /> <FormInput label="Password" name="password" type="password" value={password} onChange={this.handleChange} placeholder="Enter password..." error={errors.password} className="input" required /> <Button type="submit" label="Submit" className="button" handleClick={this.onSubmit} /> </React.Fragment> )} </React.Fragment> ); } } |
Видите, что LoginPage использует FormInput дважды? Мы используем его как для ввода текста для имени пользователя, так и для другого поля для ввода пароля. Если мы хотим внести какие-либо изменения в функции элемента ввода, мы можем внести эти изменения в созданный нами файл компонента FormInput, и они будут применены к каждому экземпляру, где используется компонент ввода. Это фундаментальный плюс наличия компонентов многократного использования: вам не нужно повторяться.
Даже ошибки отображаются из компонента FormInput. Функция onSubmit сначала проверяет объект user, который мы получаем из формы, гарантируя, что он соответствует структуре, и что значение username существует. Обратите внимание, что мы можем даже расширить функционал элемента ввода, как мы это делали, чтобы проверить, что пароль содержит не менее восьми символов.
Если вы посмотрите на код, то увидите, что в нем есть компонент Button. Это не то же самое, что HTML-элемент button, это другой компонент, который принимает свойства, которые определяют тип кнопки, которая нам нужна (передача данных, сброс, кнопка), ее имя класса, что делать при нажатии и метку. Существует множество других атрибутов кнопок, которые мы могли бы интегрировать, чтобы обеспечить выполнение любого необходимого стандарта.
1 2 3 4 5 6 7 8 9 |
const Button = (props) => ( <button type={props.type} className={props.className} onClick={props.handleClick} > {props.label} </button> ) |
Вот наша окончательная форма входа в систему, когда все компоненты собраны вместе.
Хотите поэкспериментировать сами? Попробуйте поработать с многоразовым элементом select. Если это слишком сложно, вы можете начать с элемента textarea, затем, возможно, установите чек-бокс, прежде чем переходить к select. Основная идея заключается в том, чтобы сделать его общим.
Автор: Kingsley Silas
Источник: //css-tricks.com
Редакция: Команда webformyself.