Usando texto datilografado com React - Guia para iniciantes

Amigos, na véspera do fim de semana, queremos compartilhar com vocês outra publicação interessante que queremos coincidir com o lançamento de um novo grupo no curso "Desenvolvedor JavaScript" .



Tendo passado os últimos meses desenvolvendo aplicativos e bibliotecas React usando o Typecript, decidi compartilhar algumas das coisas que aprendi durante esse período. Neste guia, vou falar sobre os modelos que utilizo para o Typecript e o React em 80% dos casos.

Devo aprender texto datilografado para reagir ao desenvolvimento de aplicativos? Vale, ainda vale a pena! Por mim, percebi na prática que a digitação estrita leva à escrita de códigos muito mais confiáveis, desenvolvimento rápido, especialmente em grandes projetos. No início, você provavelmente ficará desapontado, mas, ao trabalhar, descobrirá que pelo menos um modelo mínimo será realmente muito útil.

E se você estiver preso em algo, lembre-se de que sempre pode digitar algo como qualquer outro. Qualquer um é seu novo amigo. E agora vamos passar diretamente para exemplos.

Seu principal componente de reação com texto datilografado


Como é o componente de reação padrão no texto datilografado? Vamos comparar com o componente react em 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, } 

E agora a versão datilografada:

 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> ) } 

Muito parecido, certo? Substituímos propTypes pela interface de propTypes typescript .

O cabeçalho do prop permanece opcional, enquanto o suporte do herdeiro ainda é necessário. Exportamos nossa interface caso outro componente precisasse de um link para ela.

Estendendo atributos HTML padrão


Se quisermos que o componente pai possa fornecer atributos div digitados adicionais, como aria-hidden , style ou className , podemos defini-los na interface ou estender a interface interna. No exemplo abaixo, dizemos que nosso componente aceita qualquer propriedade div padrão, além do cabeçalho e dos descendentes.

 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> ) } 

Manipulação de eventos


Podemos tipificar manipuladores de eventos para garantir que o argumento do evento seja do tipo correto. O exemplo abaixo demonstra várias maneiras de atingir esse 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> ) } 

Não sabe qual assinatura de argumento usar? No editor, passe o mouse sobre a propriedade correspondente do manipulador de eventos.

Usando genéricos com componentes de reação


Este é um recurso mais avançado, mas é realmente poderoso. Normalmente, você define tipos de dados em componentes de reação com atributos específicos. Suponha que seu componente precise de um 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 } 

Agora vamos imaginar que você tem um componente que pode aceitar uma matriz de qualquer tipo. Os genéricos são como encomendar correspondências. O correio (nosso componente) não precisa saber o conteúdo do pacote que você está enviando, mas o remetente (componente pai) espera que o destinatário receba o conteúdo que ele enviou.

Nós o implementamos assim:

 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> ) } 

Um exemplo um pouco estranho ... no entanto, demonstra a essência. O componente aceita uma matriz de elementos de qualquer tipo, passa por ela e chama a função children como uma função de renderização com um elemento da matriz. Quando nosso componente pai fornece um renderizador de renderização como um herdador, o elemento será digitado corretamente!

Não entende? Isso é normal. Eu mesmo não descobri os genéricos até o fim, mas é improvável que você precise entendê-los completamente. No entanto, quanto mais você trabalha com typescript , mais faz sentido.

Ganchos de digitação


Os ganchos funcionam principalmente fora da caixa. As duas exceções podem ser apenas useRef e useReducer . O exemplo abaixo mostra como podemos digitar refs.

 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> } 

Nosso estado é digitado automaticamente, mas digitamos ref manualmente para indicar que ele será null ou conterá um elemento div . Quando useEffect ref na função useEffect , precisamos garantir que não seja null .

Digitação da caixa de velocidades


Com a caixa de câmbio é um pouco mais complicado, mas se for digitada corretamente, isso é ótimo.

 // 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> )) } 

Usando typeof e keyof para tipificar opções de componentes


Suponha que precisamos de um botão que possa ter uma aparência diferente, cada qual definida em um objeto com um conjunto de chaves e estilos, por exemplo:

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

Nosso componente de botão deve aceitar uma propriedade de type , que pode ser
qualquer chave do objeto de styles (por exemplo, "primário" ou "perigo" ). Podemos digitá-lo simplesmente:

 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> } 

Esses exemplos ajudarão você a percorrer 80% do caminho. Se você está preso, geralmente vale a pena
basta dar uma olhada nos exemplos de código aberto existentes.

Sancho UI é um conjunto de componentes de reação,
construído usando texto e emoção.
Blueprint é outro conjunto de componentes
react baseado em typescript .

Bem, de acordo com a tradição estabelecida, estamos aguardando seus comentários.

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


All Articles