Uso de mecanografiado con React: una guía para principiantes

Amigos, en la víspera del fin de semana queremos compartir con ustedes otra publicación interesante que queremos coincidir con el lanzamiento de un nuevo grupo en el curso "Desarrollador JavaScript" .



Después de pasar los últimos meses desarrollando aplicaciones y bibliotecas de React usando el Script mecanográfico, decidí compartir algunas de las cosas que aprendí durante ese tiempo. En esta guía, le contaré sobre las plantillas que uso para Typecript y React en el 80% de los casos.

¿Debo aprender el mecanografiado para el desarrollo de la aplicación React? Vale la pena, todavía vale la pena! Por mi parte, me di cuenta en la práctica de que la escritura estricta lleva a escribir un código mucho más confiable, un desarrollo rápido, especialmente en proyectos grandes. Al principio, probablemente se sentirá decepcionado, pero a medida que trabaje, encontrará que al menos una plantilla mínima realmente será muy útil.

Y si está atrapado en algo, recuerde que siempre puede escribir algo como cualquiera. Cualquiera es tu nuevo amigo. Y ahora pasaremos directamente a los ejemplos.

Su componente principal de reacción con mecanografiado


¿Cómo se ve el componente de reacción estándar en el mecanografiado? Comparémoslo con el componente reaccionar en javascript.

import React from 'react' import PropTypes from 'prop-types' export function StandardComponent({ children, title = 'Dr.' }) { return ( <div> {title}: {children} </div> ) } StandardComponent.propTypes = { title: PropTypes.string, children: PropTypes.node.isRequired, } 

Y ahora la versión mecanografiada:

 import * as React from 'react' export interface StandardComponentProps { title?: string children: React.ReactNode } export function StandardComponent({ children, title = 'Dr.', }: StandardComponentProps) { return ( <div> {title}: {children} </div> ) } 

Muy similar, ¿verdad? Reemplazamos propTypes con la interfaz de typescript .

El encabezado del prop sigue siendo opcional, mientras que el accesorio del heredero aún se requiere. Exportamos nuestra interfaz en caso de que otro componente necesitara un enlace.

Ampliación de los atributos HTML estándar


Si queremos que el componente padre pueda proporcionar atributos div tipo adicionales, como aria-hidden , style o className , podemos definirlos en la interface o ampliar la interfaz incorporada. En el siguiente ejemplo, decimos que nuestro componente acepta cualquier propiedad div estándar además del encabezado y los descendientes.

 import * as React from 'react' export interface SpreadingExampleProps extends React.HTMLAttributes<HTMLDivElement> { title?: string children: React.ReactNode } export function SpreadingExample({ children, title = 'Dr.', ...other }: SpreadingExampleProps) { return ( <div {...other}> {title}: {children} </div> ) } 

Manejo de eventos


Podemos tipificar manejadores de eventos para asegurarnos de que el argumento del evento sea del tipo correcto. El siguiente ejemplo muestra varias formas de lograr este objetivo:

 export interface EventHandlerProps { onClick: (e: React.MouseEvent) => void } export function EventHandler({ onClick }: EventHandlerProps) { // handle focus events in a separate function function onFocus(e: React.FocusEvent) { console.log('Focused!', e.currentTarget) } return ( <button onClick={onClick} onFocus={onFocus} onKeyDown={e => { // When using an inline function, the appropriate argument signature // is provided for us }} > Click me! </button> ) } 

¿No está seguro de qué argumento usar? En el editor, desplace el cursor sobre la propiedad correspondiente del controlador de eventos.

Uso de genéricos con componentes reactivos


Esta es una característica más avanzada, pero es realmente poderosa. Normalmente, define tipos de datos en componentes de reacción con atributos específicos. Supongamos que su componente necesita un objeto de profile .

 interface ProfileType { name: string image: string age: number | null } interface ProfilesProps { profiles: Array<ProfileType> } function Profiles(props: ProfilesProps) { // render a set of profiles } 

Ahora imaginemos que tiene un componente que puede aceptar una matriz de cualquier tipo. Los genéricos son como paquetes postales. El servicio de mensajería (nuestro componente) no necesita conocer el contenido del paquete que está enviando, pero el remitente (componente principal) espera que el destinatario reciba el contenido que envió.

Lo implementamos así:

 interface GenericsExampleProps<T> { children: (item: T) => React.ReactNode items: Array<T> } export function GenericsExample<T>({ items, children, }: GenericsExampleProps<T>) { return ( <div> {items.map(item => { return children(item) })} </div> ) } 

Un ejemplo un poco extraño ... sin embargo, demuestra la esencia. El componente toma una matriz de elementos de cualquier tipo, lo atraviesa y llama a las funciones secundarias como una función de representación con un elemento de matriz. Cuando nuestro componente padre proporciona un renderizador de renderizado como un heredero, ¡el elemento se escribirá correctamente!

No entiendo? Esto es normal Yo mismo no he descubierto los genéricos hasta el final, pero es poco probable que necesites entenderlos a fondo. Sin embargo, cuanto más trabaje con typescript , más sentido tendrá.

Ganchos de mecanografía


Los ganchos funcionan principalmente fuera de la caja. Las dos excepciones solo pueden ser useRef y useReducer . El siguiente ejemplo muestra cómo podemos escribir referencias.

 import * as React from 'react' interface HooksExampleProps {} export function HooksExample(props: HooksExampleProps) { const [count, setCount] = React.useState(0) const ref = React.useRef<HTMLDivElement | null>(null) // start our timer React.useEffect( () => { const timer = setInterval(() => { setCount(count + 1) }, 1000) return () => clearTimeout(timer) }, [count] ) // measure our element React.useEffect( () => { if (ref.current) { console.log(ref.current.getBoundingClientRect()) } }, [ref] ) return <div ref={ref}>Count: {count}</div> } 

Nuestro estado se escribe automáticamente, pero escribimos manualmente ref para indicar que será null o contendrá un elemento div . Cuando accedemos a ref en la función useEffect , debemos asegurarnos de que no sea null .

Mecanismo de caja de cambios


Con la caja de cambios es un poco más complicado, pero si está bien escrito, entonces esto es genial.

 // Yeah, I don't understand this either. But it gives us nice typing // for our reducer actions. type Action<K, V = void> = V extends void ? { type: K } : { type: K } & V // our search response type interface Response { id: number title: string } // reducer actions. These are what you'll "dispatch" export type ActionType = | Action<'QUERY', { value: string }> | Action<'SEARCH', { value: Array<Response> }> // the form that our reducer state takes interface StateType { searchResponse: Array<Response> query: string } // our default state const initialState: StateType = { searchResponse: [], query: '', } // the actual reducer function reducer(state: StateType, action: ActionType) { switch (action.type) { case 'QUERY': return { ...state, query: action.value, } case 'SEARCH': return { ...state, searchResponse: action.value, } } } interface ReducerExampleProps { query: string } export function ReducerExample({ query }: ReducerExampleProps) { const [state, dispatch] = React.useReducer(reducer, initialState) React.useEffect( () => { if (query) { // emulate async query setTimeout(() => { dispatch({ type: 'SEARCH', value: [{ id: 1, title: 'Hello world' }], }) }, 1000) } }, [query] ) return state.searchResponse.map(response => ( <div key={response.id}>{response.title}</div> )) } 

Uso de typeof y keyof para tipificar opciones de componentes


Supongamos que necesitamos un botón que puede tener una apariencia diferente, cada uno de los cuales se define en un objeto con un conjunto de teclas y estilos, por ejemplo:

 const styles = { primary: { color: 'blue', }, danger: { color: 'red', }, } 

Nuestro componente de botón debe aceptar una propiedad de type , que puede ser
cualquier clave del objeto de styles (por ejemplo, "primario" o "peligro" ). Podemos escribirlo simplemente:

 const styles = { primary: { color: 'blue', }, danger: { color: 'red', }, } // creates a reusable type from the styles object type StylesType = typeof styles // ButtonType = any key in styles export type ButtonType = keyof StylesType interface ButtonProps { type: ButtonType } export function Button({ type = 'primary' }: ButtonProps) { return <button style={styles[type]}>My styled button</button> } 

Estos ejemplos lo ayudarán a recorrer el 80% del camino. Si estás atrapado, a menudo vale la pena
solo eche un vistazo a los ejemplos de código abierto existentes.

Sancho UI es un conjunto de componentes reactivos,
construido usando mecanografiado y emoción.
Blueprint es otro conjunto de componentes
react construido en typescript .

Bueno, de acuerdo con la tradición establecida, estamos esperando sus comentarios.

Source: https://habr.com/ru/post/456124/


All Articles