Escribir una API para componentes React, parte 1: no cree accesorios conflictivos
Escribir una API para React Components, Parte 2: Dar nombres al comportamiento, no a la interacción
Escribir una API para componentes React, parte 3: el orden de los accesorios es importante
Escribir una API para React Components, Parte 4: ¡Cuidado con el Apropacalypse!
Escribir una API para React Components, Parte 5: solo use la composición
Escribimos API para componentes React, parte 6: creamos comunicación entre componentes
Hablemos de formas.
Lo más probable es que leas un montón de artículos sobre state
gestión del state
en formularios, pero este no es uno de esos artículos. En cambio, quiero hablar sobre cómo funcionan los formularios y sus API.

Están sucediendo muchas cosas aquí, eche un vistazo a la API
<Form layout="label-on-left"> <Form.Field label="Name"> <TextInput type="text" placeholder="Enter your name" /> </Form.Field> <Form.Field label="Email"> <TextInput type="email" placeholder="email@domain.com" /> </Form.Field> </Form>
Miremos cada uno de los componentes y analicémoslos:
Todo comienza con el componente Form
, que es el elemento de formulario básico con una clase adjunta. Representará todo lo que pones en él.
function Form(props) { return <form className="form">{props.children}</form> } render(<Form layout="label-on-left">...</Form>)
También acepta el layout
accesorios, lo que es útil cuando tienes poco espacio.

<Form layout="label-on-top">...</Form>
Esto cambia la forma en que se alinean las etiquetas (de derecha a izquierda) y cómo funciona el margin
.
El formulario no controla el ancho y el margin
su contenido interno. Esto ya es una preocupación para el campo de entrada dentro de este formulario.
Entonces, el componente Form
debe informar la información de layout
continuación.
La forma más fácil sería pasar el layout
usando accesorios, pero el contenido del formulario es dinámico (determinado por el desarrollador que usa este formulario), no sabemos exactamente cuál será el formulario.
Aquí es donde la API de contexto nos ayuda.
const LayoutContext = React.createContext() function Form(props) { return ( <form className="form"> <LayoutContext.Provider value={{ layout: props.layout }} > {props.children} </LayoutContext.Provider> </form> ) } export default Form export { LayoutContext }
Ahora el campo de formulario puede usar este contexto y obtener el valor del layout
El componente FormField
(campo de entrada de formulario) agrega una label
a todo lo que ingresa (por ejemplo, entrada de texto).
function Field(props) { return ( <div className="form-field"> <label {...props}>{props.label}</label> {props.children} </div> ) }
Además de esto, agrega una clase para el layout
, que proviene del contexto que creamos en el componente Form
.
import { LayoutContext } from './form' function Field(props) { return ( <LayoutContext.Consumer> {context => ( <div className={`form-field ${context.layout}`}> <label {...props}>{props.label}</label> {props.children} </div> )} </LayoutContext.Consumer> ) }
React 16.8+ useContext hook facilita la sintaxis
import { LayoutContext } from './form' function Field(props) { const context = useContext(LayoutContext) return ( <div className={`form-field ${context.layout}`}> <label {...props}>{props.label}</label> {props.children} </div> ) }
Si está interesado, aquí está el código CSS:
.form-field.label-on-left { max-width: 625px; display: flex; align-items: center; } .form-field.label-on-left label { text-align: right; width: 175px; margin-right: 25px; } .form-field.label-on-top { width: 100%; display: block; } .form-field.label-on-top label { text-align: left; margin-bottom: 25px; }
El último detalle del que quiero hablar es esta extraña sintaxis punteada para componentes.
Como Field
(el campo de entrada) siempre se usa con un formulario, tiene sentido agruparlos.
Una forma de hacerlo es exportarlo desde el mismo archivo:
import Field from './field' function Form(props) { } export default Form export { Field }
Y ahora los usuarios pueden importarlos juntos:
import Form, { Field } from 'components/form' render( <Form> <Field>...</Field> </Form> )
Podemos hacer una pequeña mejora adjuntando Field
al mismo componente del formulario.
import Field from './field' function Form(props) { } Form.Field = Field export default Form
Este código funciona porque los componentes React son objetos javascript, y puede agregar claves adicionales a estos objetos.
Para el usuario, esto significa que cuando importa un Form
, recibe un Field
automáticamente.
import Form from 'components/form' render( <Form> <Form.Field>...</Form.Field> </Form> )
Realmente me gusta esta API, hace que la conexión entre Form
y Form.Field
obvia.
Nota: debe mover el contexto a otro archivo para evitar la dependencia circular.
La combinación de sintaxis con puntos y contexto hace que nuestro componente Form
inteligente, al tiempo que mantiene su operatividad para composiciones (compuestas).