1 | # Hooks
|
2 |
|
3 | La sintaxis de Atomico se basa en la experiencia funcional heredada de React, Atomico aplica este comportamiento funcional para crear web-components con un código legible, sostenible y simple ... Gracias React.
|
4 |
|
5 | 1. core
|
6 | 1. [useState](#usestate)
|
7 | 2. [useEffect](#useeffect)
|
8 | 3. [useMemo](#usememo)
|
9 | 4. [useRef](#useref)
|
10 | 5. [useProp](#useprop)
|
11 | 2. atomico/lazy
|
12 | 1. [useLazy](#uselazy)
|
13 | 3. atomico/router
|
14 | 1. [useRouter](#userouter)
|
15 | 2. [useRoute](#useroute)
|
16 | 3. [useRedirect](#useredirect)
|
17 | 4. atomico/use-state-generator
|
18 | 1. [useStateGenerator](#usestategenerator)
|
19 |
|
20 | ## useState
|
21 |
|
22 | crea un estado local en el web-component
|
23 |
|
24 | ```jsx
|
25 | let [state, setState] = useState(initialState);
|
26 | ```
|
27 |
|
28 | Donde :
|
29 |
|
30 | * `state` es el estado actual del hook.
|
31 |
|
32 | * `setState` es una función que modifica el estado actual.
|
33 |
|
34 | > **De ser función** será ejecutada recibiendo como argumento el estado actual para retornar el siguiente estado
|
35 |
|
36 | * `initialState` es el estado inicial
|
37 |
|
38 | > **De ser función** será ejecutada para retornar el estado inicial
|
39 |
|
40 | #### Ejemplo
|
41 |
|
42 | ```jsx
|
43 | let [count, setCount] = useState(0);
|
44 |
|
45 | function increment() {
|
46 | setCount(count + 1);
|
47 | }
|
48 |
|
49 | <host>
|
50 | count : {count}
|
51 | <button onclick={increment}>increment</button>
|
52 | </host>;
|
53 | ```
|
54 |
|
55 | Donde :
|
56 |
|
57 | * `count` es el estado actual, inicializando en `0`
|
58 | * `increment` es el actualizador de estado mediante el uso de `setCount`
|
59 |
|
60 | ## useEffect
|
61 |
|
62 | crea un efecto secundario asociado al ciclo de render, útil para controlar efectos que interactúen con el DOM o asincronía
|
63 |
|
64 | ```jsx
|
65 | function afterRender() {
|
66 | console.log("after render");
|
67 | return beforeNewRender;
|
68 | }
|
69 |
|
70 | function beforeNewRender() {
|
71 | console.log("new render");
|
72 | }
|
73 |
|
74 | useEffect(afterRender, optionalArgument);
|
75 | ```
|
76 |
|
77 | Donde:
|
78 |
|
79 | * `afterRender` es una función que se ejecuta después del render asociado al hook
|
80 | * `beforeNewRender` es el retorno de la funcion `afterRender` y esta sera ejecutada solo si se genera un nuevo render o se desmonta el hook
|
81 |
|
82 | Considere que en el ejemplo las funciones se separan para definir su uso, se recomienda que el callback de retorno siempre exista dentro de la función que requiere useEffect, ya que el objetivo es la limpieza de eventos que se generan en el scope ejecución del hook, como se enseña en el siguiente ejemplo:
|
83 |
|
84 | #### Ejemplo
|
85 |
|
86 | ```jsx
|
87 | let [route, setRoute] = useState(location.pathname);
|
88 |
|
89 | useEffect(() => {
|
90 | function handler() {
|
91 | setRoute(location.pathname);
|
92 | }
|
93 | window.addEventListener("popstate", handler);
|
94 | return () => window.removeEventListener("popstate", handler);
|
95 | }, []);
|
96 | ```
|
97 |
|
98 | En el ejemplo useEffect se ejecutara solo una vez indiferente a la cantida de actualizaciones asociada, siendo esto de utilidad para la suscripción de eventos externos al hook.
|
99 |
|
100 | ## useMemo
|
101 |
|
102 | memoriza el retorno de un callback limitando su ejecución mediante un array de argumentos, este se ejecuta en el momento del render
|
103 |
|
104 | ```jsx
|
105 | let data = useMemo(
|
106 | () => {
|
107 | for (let i = 0; i < length; i++) {
|
108 | data.push({ key: i, ...placeholder });
|
109 | }
|
110 | },
|
111 | [length]
|
112 | );
|
113 | ```
|
114 |
|
115 | ## useRef
|
116 |
|
117 | permite crear una referencia que se mantiene mutable entre renders.
|
118 |
|
119 | ```js
|
120 | let ref = useRef(optionalCurrent);
|
121 | ```
|
122 |
|
123 | Donde:
|
124 |
|
125 | * `ref` es un objeto que no muta entre renders
|
126 | * `opcionalCurrent` es el estado inicial de la propiedad `ref.current`
|
127 |
|
128 | #### Ejemplo
|
129 |
|
130 | ```jsx
|
131 | let ref = useRef();
|
132 |
|
133 | useEffect(
|
134 | () => {
|
135 | ref.current.addEventListener("click", ({ target }) => {
|
136 | console.log({ target });
|
137 | });
|
138 | },
|
139 | [ref]
|
140 | );
|
141 |
|
142 | <host>
|
143 | <button ref={ref}> click </button>
|
144 | </host>;
|
145 | ```
|
146 |
|
147 | El en ejemplo la variable `ref` se entrega al virtual-dom, este definirá en el momento de la renderizacion el nodo como `ref.current`, permitiendo acceder a este después del render.
|
148 |
|
149 | ## useProp
|
150 |
|
151 | accede a una propiedad(props) previamente declarada sobre el contenedor(web-component), **permitiendo manipular desde el ciclo de render el estado de estas propiedades**.
|
152 |
|
153 | ```jsx
|
154 | let [value, setValue] = useProp(propName);
|
155 | ```
|
156 |
|
157 | Donde :
|
158 |
|
159 | * `value` es el estado actual de la propiedad asociada al web-component
|
160 | * `setValue` es una función encargada de actualizar el estado
|
161 | * `propsName` es el nombre de la propiedad a modificar por `useProp`
|
162 |
|
163 | #### Ejemplo
|
164 |
|
165 | ```jsx
|
166 | let [count, setCount] = useProp("count");
|
167 |
|
168 | <host>
|
169 | count : {count}
|
170 | <button onclick={() => setCount(count + 1)}>increment</button>
|
171 | </host>;
|
172 | ```
|
173 |
|
174 | Ante cada cambio de count ud podrá leer estos cambios mediante la propiedad count asociada al nodo del DOM asociada al web-component, ej `nodeWebComponent.count`
|
175 |
|
176 | # atomico/lazy
|
177 |
|
178 | ```jsx
|
179 | import { useLazy } from "atomico/lazy";
|
180 | ```
|
181 |
|
182 | ## useLazy
|
183 |
|
184 | crea un nodo asíncrono ideal para el uso de import o request.
|
185 |
|
186 | #### Ejemplo dinamic import
|
187 |
|
188 | ```jsx
|
189 | let UiHeader = useLazy(() =>
|
190 | import("./src/web-components/ui-header/ui-header")
|
191 | );
|
192 |
|
193 | return (
|
194 | <host>
|
195 | <UiHeader loading="...loading" />
|
196 | </host>
|
197 | );
|
198 | ```
|
199 |
|
200 | #### Ejemplo request
|
201 |
|
202 | ```jsx
|
203 | let UiItems = useLazy(async () => {
|
204 | let request = await fetch(`https://jsonplaceholder.typicode.com/posts`);
|
205 | let data = await request.json();
|
206 | return data.map(({ body }) => <div>{body}</div>);
|
207 | });
|
208 |
|
209 | return (
|
210 | <host>
|
211 | <UiItems loading="...loading" />
|
212 | </host>
|
213 | );
|
214 | ```
|
215 |
|
216 | > El nodo que retorna useLazy posee 2 propiedades `loading` y `error`, las que pueden una función o un nodo virtual
|
217 |
|
218 | #### Ejemplo 2 argumento
|
219 |
|
220 | El segundo argumento en para `useLazy`, permite regenerar el efecto de lazy, de forma similar a lo que ocurre con `useEffect`.
|
221 |
|
222 | ```jsx
|
223 | let [id, setId] = useState(1);
|
224 |
|
225 | let User = useLazy(
|
226 | async () => {
|
227 | let request = await fetch(
|
228 | `https://jsonplaceholder.typicode.com/users/${id}`
|
229 | );
|
230 | let data = await request.json();
|
231 |
|
232 | return (
|
233 | <ul>
|
234 | <li>username : {data.username}</li>
|
235 | <li>email : {data.email}</li>
|
236 | </ul>
|
237 | );
|
238 | },
|
239 | [id]
|
240 | );
|
241 |
|
242 | return (
|
243 | <host>
|
244 | <button onclick={() => setState(0)}>user 1</button>
|
245 | <button onclick={() => setState(1)}>user 1</button>
|
246 | <button onclick={() => setState(2)}>user 2</button>
|
247 | <User loading={`...loading user ${id}`} />
|
248 | </host>
|
249 | );
|
250 | ```
|
251 |
|
252 | [Ejemplo](https://codepen.io/uppercod/pen/BaaMORB?editors=1010)
|
253 |
|
254 | # atomico/router
|
255 |
|
256 | ```js
|
257 | import { useRouter, useRoute, useRedirect } from "atomico/router";
|
258 | ```
|
259 |
|
260 | ## useRouter
|
261 |
|
262 | define desde un objeto la vista actual a utilizar a base de la ruta actual
|
263 |
|
264 | ```jsx
|
265 | let paths = {
|
266 | "/": () => <WebComponentHome />,
|
267 | "/user/:id": ({ id }) => <WebComponentUser id={id} />,
|
268 | default: <h1>404</h1>
|
269 | };
|
270 | let View = useRouter(paths);
|
271 | ```
|
272 |
|
273 | Donde :
|
274 |
|
275 | * `paths` objeto que define las expreciones para que `useRouter` realize la comprovacion que define a `View`
|
276 | * `View` es el retorno de la expresión asociada a `paths`.
|
277 |
|
278 | ## useRoute
|
279 |
|
280 | define si una ruta esta activa y optiene los parametros de esta
|
281 |
|
282 | ```jsx
|
283 | let [inRoute, paramsRoute] = useRoute("/:id?");
|
284 | ```
|
285 |
|
286 | Donde :
|
287 |
|
288 | * `inRoute` **Booleano** que defin cvv xc cv e si la expresión concuerda con la expresión dada a `useRoute`.
|
289 |
|
290 | * `paramsRoute` **Objeto** que define los parámetros capturados por la expresión dada a `useRoute`.
|
291 |
|
292 | #### Comodines de useRoute y useRouter
|
293 |
|
294 | | Comodin | descripcion |
|
295 | | ---------- | ------------------------- |
|
296 | | `/static` | Ruta requerida |
|
297 | | `/:id` | parámetros obligatorio |
|
298 | | `/:id?` | parámetro opcional |
|
299 | | `/:any...` | parámetro opcional spread |
|
300 |
|
301 | ## useRedirect
|
302 |
|
303 | ```jsx
|
304 | let goHome = useRedirect("/");
|
305 | ```
|
306 |
|
307 | # atomico/use-state-generator
|
308 |
|
309 | ```js
|
310 | import { useStateGenerator, delay } from "atomico/use-state-generator";
|
311 | ```
|
312 |
|
313 | ## useStateGenerator
|
314 |
|
315 | Este hook permite consumir generadores o funciones asíncronas para definir un estado, este consumo es recursivo por lo que ud puede usarlo para streaming complejos de data y concurrencia.
|
316 |
|
317 | ```jsx
|
318 | let [state, promise] = useStateGenerator(callbackGenerator, initialState, vars);
|
319 | ```
|
320 |
|
321 | Donde :
|
322 |
|
323 | * `state` es el estado actual del hook.
|
324 | * `promise` es una promesa que define si el proceso asincrono de `useStateGenerator` ha finalizado.
|
325 | * `callbackGenerator` es una funcion sea asincrona, generador o generador asincrono a consumir por `useStateGenerator`.
|
326 | * `initialState`, estado inicial del hook.
|
327 | * `vars` es un array de variables a observar entre renders, de ser distinto uno de estos elementos regenera el hook ejecutando nuevamente `callbackGenerator`.
|
328 |
|
329 | #### Ejemplo
|
330 |
|
331 | ```jsx
|
332 | import { useStateGenerator, delay}
|
333 | /** inside web-component */
|
334 | let length = 10;
|
335 | let [state] = useStateGenerator((state)=>{
|
336 | while(--state){
|
337 | yield delay(1000);
|
338 | yield state;
|
339 | }
|
340 | return state;
|
341 | },0, [length])
|
342 | ```
|
343 |
|
344 | El ejemplo anterior genera una cuenta regresiva de 10..1, cada paso es de 1000ms.
|