useReact("better")
el hook de las buenas prácticas
Joel A. Villarreal Bertoldi
🏳🌈 ¡Hola, soy Joey!
Soy co-fundador de CoDeAr y trabajo en Mercado Libre como líder técnico. Programo hace más de 20 años. Me gustan los unicornios 🦄 (y los cactus 🌵)
cuento cosas en Twitter
@joelalejandro
desmitificando
TypeScript
en React
is the cake a lie?
hablemos de
PropTypes
Es la forma que nos ofrece React para validar el tipo de datos de las propiedades de nuestros componentes.
const Button = (props) => {
const children = props.children;
const type = props.type;
return (
<button type={type} className="ui-button">
{children}
</button>
);
}
¿Cómo valido que children y type
tengan valores coherentes?
const Button = (props) => {
const children = props.children;
const type = props.type;
return (
<button type={type} className="ui-button">
{children}
</button>
);
}
Button.propTypes = {
children: PropTypes.node,
type: PropTypes.string,
};
¿Y en TypeScript?
const Button = (props) => {
const children = props.children;
const type = props.type;
return (
<button type={type} className="ui-button">
{children}
</button>
);
}
Button es un componente funcional.
(¿Por qué? Porque no utilizamos una clase que extienda de React.Component)
const Button: React.FC = (props) => {
const children = props.children;
const type = props.type;
return (
<button type={type} className="ui-button">
{children}
</button>
);
}
Podemos tiparlo utilizando React.FC.
Pero ¿y las props?
const Button: React.FC<{type: string}> = (props) => {
const children = props.children;
const type = props.type;
return (
<button type={type} className="ui-button">
{children}
</button>
);
}
Aprovechando el sistema de genericidad de TypeScript, podemos subtipar nuestras propiedades.
Pero ¿y "children"?
En React, props está definido como de tipo PropsWithChildren<T>.
A cualquier tipo que definamos para props, le anexará automáticamente una propiedad children.
props: React.PropsWithChildren<T>
PropsWithChildren<T> = T & {children?: React.ReactNode}
const Button: React.FC<{type: string}> = (props) => {
const children = props.children;
const type = props.type;
return (
<button type={type} className="ui-button">
{children}
</button>
);
}
¿Podemos ser más específicos en la declaración del tipo de las propiedades de este componente?
¡Sí! Definimos un tipo ButtonProps con la definición exacta de qué puede recibir type como valores permitidos y pasamos este tipo como parámetro a React.FC.
type ButtonProps = {
type: "submit" | "button"
};
const Button: React.FC<ButtonProps> = (props) => {
const children = props.children;
const type = props.type;
return (
<button type={type} className="ui-button">
{children}
</button>
);
}
Pero entonces hasta acá, ¿cuál es la ventaja con respecto a PropTypes?
PropTypes
Run-time
TypeScript
Build-time
veamos un poco de
State Management
¿Cómo manejamos el estado de un árbol de componentes?
Puede ser muy tentador instalar dependencias como Redux, MobX o cualquiera de sus símiles.
¿Es absolutamente necesario?
import React from "react";
export type InputValues<T = string | number> = { [key: string]: T }
export type FormContextProps = {
inputValues: InputValues;
}
const FormContext = React.createContext<FormContextProps>({
inputValues: {}
});
export default FormContext;
import React from "react";
import FormContext from "./FormContext";
import useFormContext from "../../hooks/useFormContext";
const Form: React.FC = (props) => {
const [formContext] = useFormContext();
const { children } = props;
return <form>
<FormContext.Provider value={formContext}>
{children}
</FormContext.Provider>
</form>
};
export default Form;
FormContext.ts
Form.tsx
import React from "react";
import useFormContext from "../../hooks/useFormContext";
export type InputProps = {
type: string;
value: string | number;
name: string;
}
const Input: React.FC<InputProps> = (props) => {
const [formContext, updateFormContext] = useFormContext();
return <input
onChange={({ target }) => updateFormContext(props.name, target.value)}
value={formContext[props.name]}
{...props} />
};
export default Input;
Input.tsx
y ya que estamos enganchades, hablamos de
Hoooooks
Pero no de los hooks de React... si no de ¡los hooks que podemos inventar!
import React from "react";
import FormContext from "./FormContext";
import useFormContext from "../../hooks/useFormContext";
const Form: React.FC = (props) => {
const [formContext] = useFormContext();
const { children } = props;
return <form>
<FormContext.Provider value={formContext}>
{children}
</FormContext.Provider>
</form>
};
export default Form;
import { useContext } from "react";
import FormContext, { FormContextProps } from "../components/form/FormContext";
const createFormContextUpdater = (
formContext: FormContextProps
) => (
inputName: string, inputValue: string | number
) => {
formContext.inputValues[inputName] = inputValue;
};
const useFormContext = () => {
const formContext = useContext(FormContext);
return [
formContext,
createFormContextUpdater(formContext)
] as const;
}
export default useFormContext;
import React from "react";
import useFormContext from "../../hooks/useFormContext";
export type InputProps = {
type: string;
value: string | number;
name: string;
}
const Input: React.FC<InputProps> = (props) => {
const [formContext, updateFormContext] = useFormContext();
return <input
onChange={({ target }) => updateFormContext(props.name, target.value)}
value={formContext[props.name]}
{...props} />
};
export default Input;
¿Preguntas?
useReact("better") - vOpen Tech 2020
By Joel Alejandro Villarreal Bertoldi
useReact("better") - vOpen Tech 2020
Una charla sobre buenas prácticas en torno a TypeScript, hooks nativos y personalizados, brindada en vOpen Tech 2020.
- 394