json-api-normalizer: una forma sencilla de integrar la API JSON y Redux

 

 

 


Índice
  1. Trasfondo
  2. Mejores prácticas de Redux
  3. Mejor práctica 1: mantener los datos planos en la tienda Redux
    1. 2. Almacene las colecciones como mapas siempre que sea posible
    2. /alicia/amigos Respuesta
    3. /bob/amigos Respuesta
    4. Estado de almacenamiento
    5. Estado de almacenamiento con metadatos
    6. Estado de almacenamiento revisado
  4. Procesamiento de datos y API JSON
  5. API JSON vs. Servicios web típicos
    1. Un documento JSON típico
    2. Documento API JSON
  6. API JSON y Redux
  7. Implementación de la aplicación de demostración
  8. 1. Descargue el texto estándar
  9. 2. Integración de API
    1. src/redux/middleware/api.js
    2. src/redux/configureStore.js
    3. src/redux/acciones/post.js
    4. src/redux/reductores/data.js
    5. src/redux/reductores/data.js
    6. src/components/Content.jsx
  10. 3. Obteniendo los datos de la tienda
    1. src/components/Content.jsx

Para cada aplicación en la que trabaja Yury Dymov, debe decidir cómo gestionar los datos. El problema se puede dividir en los siguientes tres subproblemas: recuperar datos del back-end, almacenarlos en algún lugar local de la aplicación de front-end, recuperar los datos del almacén local y formatearlos según lo requiera la vista o pantalla en particular. En este artículo, Yury resume su experiencia con el consumo de datos de JSON, la API JSON y los backends GraphQL, y brinda recomendaciones prácticas sobre cómo administrar los datos de las aplicaciones front-end.

 

Como desarrollador front-end, para todas y cada una de las aplicaciones en las que trabajo, necesito decidir cómo gestionar los datos. El problema se puede dividir en los siguientes tres subproblemas:

  1. recuperar datos desde el back-end,
  2. guárdelo en algún lugar local de la aplicación front-end,
  3. recupere los datos del almacén local y formatéelos según lo requiera la vista o pantalla en particular.

Este artículo resume mi experiencia con el consumo de datos de JSON, la API JSON y los backends GraphQL, y ofrece recomendaciones prácticas sobre cómo administrar los datos de las aplicaciones front-end.

Creación de restablecimientos de contraseña seguros con tokens web JSON

¿Su sitio todavía envía recordatorios de contraseña por correo electrónico? Esto debería ser una señal de alerta para usted, tanto como usuario como desarrollador. Veamos cómo crear restablecimientos de contraseña seguros con tokens web JSON.Leer un artículo relacionado →

Para ilustrar mis ideas y acercar el artículo a casos de uso del mundo real, desarrollaré una aplicación front-end muy simple al final del artículo. Imaginemos que hemos implementado una encuesta que plantea el mismo montón de preguntas a muchos usuarios. Después de que cada usuario haya proporcionado sus respuestas, otros usuarios pueden comentarlas si lo desean. Nuestra aplicación web realizará una solicitud al back-end, almacenará los datos obtenidos en la tienda local y mostrará el contenido en la página. Para simplificar las cosas, omitiremos el flujo de creación de respuestas.

También hay una demostración en vivo disponible en GitHub.

Trasfondo

En los últimos años, he participado en muchos proyectos front-end basados ​​en la pila React. Usamos Redux para administrar el estado no solo porque es la solución más utilizada en su categoría, según la reciente encuesta sobre el estado de JavaScript en 2016 , sino que también es muy liviana, sencilla y predecible. Sí, a veces requiere escribir mucho más código repetitivo que otras soluciones de gestión estatal; sin embargo, puede comprender y controlar completamente cómo funciona su aplicación, lo que le brinda mucha libertad para implementar cualquier lógica y escenario de negocios.

 

Para darle un poco de contexto, hace algún tiempo probamos GraphQL y Relay en una de nuestras pruebas de concepto. No me malinterpretes: funcionó muy bien. Sin embargo, cada vez que queríamos implementar un flujo ligeramente diferente al estándar, terminamos peleando con nuestra pila, en lugar de ofrecer nuevas funciones. Sé que muchas cosas han cambiado desde entonces y Relay es una solución decente ahora, pero aprendimos por las malas que usar herramientas simples y predecibles funciona mejor para nosotros porque podemos planificar nuestro proceso de desarrollo con mayor precisión y cumplir mejor con nuestros plazos .

Nota: Antes de seguir adelante, asumo que tienes algunos conocimientos básicos de gestión estatal y de Flux o Redux.

Mejores prácticas de Redux

Lo mejor de Redux es que no tiene opiniones sobre qué tipo de API consume. Incluso puede cambiar su API de JSON a JSON API o GraphQL y viceversa durante el desarrollo, y siempre que conserve su modelo de datos, no afectará en absoluto la implementación de su gestión de estado. Esto es posible porque, antes de enviar la respuesta API a la tienda, la procesarías de cierta manera. Redux en sí no te obliga a hacer eso; sin embargo, la comunidad ha identificado y desarrollado varias mejores prácticas basadas en experiencias del mundo real . Seguir estas prácticas le ahorrará mucho tiempo al reducir la complejidad de sus aplicaciones y disminuir la cantidad de errores y casos extremos.

Mejor práctica 1: mantener los datos planos en la tienda Redux

Volvamos a la aplicación de demostración y analicemos el modelo de datos:

Aquí tenemos un questionobjeto de datos, que puede tener muchos postobjetos. Cada uno postpuede tener muchos commentobjetos. Cada uno posty commenttiene uno author, respectivamente.

Supongamos que tenemos un backend que devuelve una respuesta JSON típica. Es muy probable que tenga una estructura profundamente anidada. Si prefiere almacenar sus datos de manera similar en la tienda, tarde o temprano enfrentará muchos problemas. Por ejemplo, podrías almacenar el mismo objeto varias veces. Es posible postque tengas commentobjetos que comparten lo mismo author. Tu tienda se vería así:

{ "text": "My Post", "author": { "name": "Yury", "avatar": "avatar1.png" }, "comments": [ { "text": "Awesome Comment", "author": { "name": "Yury", "avatar": "avatar1.png" } } ]}

Como puede ver, almacenamos el mismo Authorobject en varios lugares, lo que no sólo requiere más memoria sino que también tiene efectos secundarios negativos. Imagínese si en el back-end alguien cambiara el avatar del usuario. En lugar de actualizar un objeto en la tienda Redux, ahora necesitarás recorrer todo el estado y actualizar todas las instancias del mismo objeto. No sólo podría ser muy lento, sino que también requeriría que usted aprenda con precisión la estructura del objeto de datos.

 

La refactorización también sería una pesadilla. Otro problema es que si decide reutilizar ciertos objetos de datos para nuevas vistas y están anidados en otros objetos, la implementación transversal sería compleja, lenta y sucia.

En cambio, podemos almacenar los datos en una estructura aplanada. De esta forma, cada objeto se almacenaría solo una vez y tendríamos muy fácil acceso a cualquier dato.

{ "post": [{ "id": 1, "text": "My Post", "author": { "id": 1 }, "comments": [ { "id": 1 } ] }], "comment": [{ "id": 1, "text": "Awesome Comment" }], "author": [{ "name": "Yury", "avatar": "avatar1.png", "id": 1 }] }

Los mismos principios se han utilizado ampliamente en los sistemas de gestión de bases de datos relacionales durante muchos años.

2. Almacene las colecciones como mapas siempre que sea posible

Bien, entonces tenemos los datos en una bonita estructura plana. Es una práctica muy común acumular incrementalmente los datos recibidos, para poder reutilizarlos más tarde como caché, para mejorar el rendimiento o para uso sin conexión .

Sin embargo, después de fusionar datos nuevos en el almacenamiento existente, debemos seleccionar solo los objetos de datos relevantes para la vista particular, no todos los que hemos recibido hasta ahora. Para lograr esto, podemos almacenar la estructura de cada documento JSON por separado, de modo que podamos determinar rápidamente qué objetos de datos se proporcionaron en una solicitud particular . Esta estructura contendría una lista de ID de objetos de datos, que podríamos usar para recuperar los datos del almacenamiento.

Permítanme ilustrar este punto. Realizaremos dos solicitudes para obtener una lista de amigos de dos usuarios diferentes, Alice y Bob, y revisaremos el contenido de nuestro almacenamiento en consecuencia. Para facilitar las cosas, supongamos que, al principio, el almacenamiento está vacío.

/alicia/amigos Respuesta

Entonces, aquí obtenemos el Userobjeto de datos con un ID 1y un nombre de Mike, que podría almacenarse de esta manera:

{ "data": [{ "type": "User", "id": "1", "attributes": { "name": "Mike" } }]}

/bob/amigos Respuesta

Otra solicitud devolvería un Usercon el ID 2y el nombre de Kevin:

{ "data": [{ "type": "User", "id": "2", "attributes": { "name": "Kevin" } }]}

Estado de almacenamiento

Después de fusionar, nuestro almacenamiento se vería así:

{ "users": [ { "id": "1", "name": "Mike" }, { "id": "2", "name": "Kevin" } ]}

La gran pregunta es, ¿cómo podemos distinguir a partir de este punto qué usuarios son amigos de Alice y cuáles son amigos de Bob?

Estado de almacenamiento con metadatos

Podríamos preservar la estructura del documento API JSON, de modo que podamos descubrir rápidamente qué objetos de datos almacenados son relevantes. Teniendo esto en cuenta, podríamos cambiar la implementación del almacenamiento para que se vea así:

 

{ "users": [ { "id": "1", "name": "Mike" }, { "id": "2", "name": "Kevin" } ], "meta": { "/alice/friends": [ { "type": "User", "id": "1" } ], "/bob/friends": [ { "type": "User", "id": "2" } ] }}

Ahora podemos leer los metadatos y recuperar todos los objetos de datos mencionados. ¡Problema resuelto! ¿Podemos hacerlo mejor? Tenga en cuenta que constantemente realizamos tres operaciones: insertar, leer y fusionar. ¿Qué estructura de datos funcionará mejor para nosotros?

Recapitulemos brevemente las complejidades de la operación.

Tipo Agregar Borrar Buscar Preserva el orden
Mapa O(1) O(1) O(1) No
Formación O(1) En) En)

Nota: Si no está familiarizado con la notación Big O , naquí se refiere al número de objetos de datos, O(1)significa que la operación tomará relativamente la misma cantidad de tiempo independientemente del tamaño del conjunto de datos y O(n)significa que el tiempo de ejecución de la operación depende linealmente de el tamaño del conjunto de datos.

Como podemos ver, los mapas funcionarán mucho mejor que las matrices porque todas las operaciones tienen una complejidad de O(1), en lugar de O(n). Si el orden de los objetos de datos es importante, aún podemos usar mapas para el manejo de datos y guardar la información de pedido en los metadatos. Los mapas también se pueden transformar fácilmente en matrices y ordenar, si es necesario.

Reimplementemos el almacenamiento mencionado anteriormente y usemos un mapa en lugar de una matriz para el Userobjeto de datos.

Estado de almacenamiento revisado

{ "users": { "1": { "name": "Mike" }, "2": { "name": "Kevin" } }, "meta": { "/alice/friends": [ { "type": "User", "id": "1" } ], "/bob/friends": [ { "type": "User", "id": "2" } ] }}

Ahora, en lugar de recorrer toda la matriz para encontrar un usuario en particular, podemos obtenerlo por ID casi al instante.

Procesamiento de datos y API JSON

Como puede imaginar, debería haber una solución ampliamente utilizada para convertir documentos JSON a un formato compatible con Redux. La biblioteca Normalizr fue desarrollada inicialmente por Dan Abramov, autor de Redux, para este propósito. Debe proporcionar un documento JSON y el esquema para "normalizar" la función, y devolverá los datos en una estructura plana agradable, que podemos guardar en la tienda Redux.

Hemos utilizado este enfoque en muchos proyectos y, si bien funciona muy bien si su modelo de datos se conoce de antemano y no cambiará mucho durante el ciclo de vida de la aplicación, falla dramáticamente si las cosas son demasiado dinámicas. Por ejemplo, cuando crea un prototipo, desarrolla una prueba de concepto o crea un nuevo producto, el modelo de datos cambiará con mucha frecuencia para adaptarse a nuevos requisitos y solicitudes de cambio. Cada cambio de back-end debe reflejarse en una actualización del esquema Normalizr. Debido a esto, varias veces terminé peleando con mi aplicación de front-end para arreglar cosas, en lugar de trabajar en nuevas funciones. Recetas de Postres peruanos

 

¿Hay alguna alternativa? Probamos GraphQL y la API JSON.

Si bien GraphQL parece muy prometedor y podría ser una opción interesante, no pudimos adoptarlo en ese momento porque muchas terceras partes consumían nuestras API y no podíamos simplemente abandonar el enfoque REST.

Analicemos brevemente el estándar API JSON .

API JSON vs. Servicios web típicos

Estas son las características principales de la API JSON:

  • Los datos se representan en una estructura plana, con relaciones de no más de un nivel de profundidad.
  • Los objetos de datos están tipificados.
  • La especificación define funciones de paginación, clasificación y filtrado de datos listas para usar.

Un documento JSON típico

{ "id": "123", "author": { "id": "1", "name": "Paul" }, "title": "My awesome blog post", "comments": [ { "id": "324", "text": "Great job, bro!", "commenter": { "id": "2", "name": "Nicole" } } ]}

Documento API JSON

{ "data": [{ "type": "post", "id": "123", "attributes": { "id": 123, "title": "My awesome blog post" }, "relationships": { "author": { "type": "user", "id": "1" }, "comments": { "type": "comment", "id": "324" } } }], "included": [{ "type": "user", "id": "1", "attributes": { "id": 1, "name": "Paul" } }, { "type": "user", "id": "2", "attributes": { "id": 2, "name": "Nicole" } }, { "type": "comment", "id": "324", "attributes": { "id": 324, "text": "Great job!" }, "relationships": { "commenter": { "type": "user", "id": "2" } } }]}

La API JSON puede parecer demasiado detallada en comparación con el JSON tradicional, ¿verdad?

Tipo Sin formato (bytes) comprimido (bytes)
JSON típico 264 170
API JSON 771 293

Si bien la diferencia de tamaño bruto puede ser notable, los tamaños comprimidos con Gzip están mucho más cerca uno del otro.

Tenga en cuenta que también es posible desarrollar un ejemplo artificial cuyo tamaño en un formato JSON típico sea mayor que el de la API JSON. Imagine docenas de publicaciones de blog que comparten el mismo autor. En un documento JSON típico, tendría que almacenar el authorobjeto para cada postobjeto, mientras que en el formato API JSON, el authorobjeto se almacenaría solo una vez.

La conclusión es que sí, el tamaño promedio del documento JSON API es mayor, pero no debería considerarse un problema. Normalmente, se trata de datos estructurados, que se comprimen a una quinta parte de su tamaño o más y que también son relativamente pequeños gracias a la paginación.

 

Analicemos las ventajas:

  • En primer lugar, la API JSON devuelve datos en forma plana, sin más de un nivel de relaciones. Esto ayuda a evitar la redundancia y garantiza que cada objeto único se almacenará en un documento sólo una vez. Este enfoque es una combinación perfecta para las mejores prácticas de Redux y pronto usaremos esta función.
  • En segundo lugar, los datos se proporcionan en forma de objetos tipificados, lo que significa que en el lado del cliente no es necesario implementar analizadores ni definir esquemas como lo hace con Normalizr . Esto hará que sus aplicaciones front-end sean más flexibles a los cambios en la estructura de datos y requerirá menos esfuerzo de su parte para adaptar la aplicación a los nuevos requisitos.
  • En tercer lugar, la especificación JSON API define un linksobjeto, lo que ayuda a mover la paginación y a filtrar y ordenar funciones desde su aplicación a los clientes JSON API. También está disponible un objeto opcional meta, donde puede definir la carga útil específica de su aplicación.

API JSON y Redux

Redux y la API JSON funcionan muy bien cuando se usan juntos; se complementan bien.

La API JSON proporciona datos en una estructura plana por definición, lo que se ajusta muy bien a las mejores prácticas de Redux. Los datos vienen tipificados, para que puedan guardarse naturalmente en el almacenamiento de Redux en un mapa con el formato type→ mapa de objetos.

Entonces, ¿nos falta algo?

A pesar de que dividir los objetos de datos en dos tipos, "datos" e "incluidos", puede tener algún sentido para la aplicación, no podemos darnos el lujo de almacenarlos como dos entidades separadas en el almacén de Redux, porque entonces los mismos objetos de datos se almacenaría más de una vez, lo que viola las mejores prácticas de Redux.

Como comentamos, la API JSON también devuelve una colección de objetos en forma de matriz, pero para la tienda Redux, usar un mapa es mucho más adecuado.

Para resolver estos problemas, considere usar mi biblioteca json-api-normalizer .

Estas son las características principales de json-api-normalizer:

  • Fusionar datos y campos incluidos, normalizando los datos.
  • Las colecciones se convierten en mapas en forma a id= object.
  • La estructura original de la respuesta se almacena en un metaobjeto especial.

En primer lugar, se introdujo una distinción entre datos y objetos de datos incluidos en la especificación JSON API, para resolver problemas con estructuras recursivas y dependencias circulares. En segundo lugar, la mayoría de las veces, los datos en Redux se actualizan de forma incremental , lo que ayuda a mejorar el rendimiento y tiene soporte fuera de línea. Sin embargo, como trabajamos con los mismos objetos de datos en nuestra aplicación, a veces no es posible distinguir qué objetos de datos debemos usar para una vista particular. json-api-normalizer puede almacenar la estructura de la respuesta de un servicio web en un metacampo especial, de modo que pueda determinar sin ambigüedades qué objetos de datos se obtuvieron para una solicitud API particular.

 

Implementación de la aplicación de demostración

Nota: supongo que tienes alguna experiencia práctica con React y Redux.

Una vez más, crearemos una aplicación web muy simple que representará los datos de la encuesta proporcionados por el back-end en formato JSON API.

Comenzaremos con el texto estándar, que tiene todo lo que necesitamos para la aplicación React básica; implementaremos middleware Redux para procesar los documentos API JSON; proporcionaremos los datos de los reductores en un formato adecuado; y construiremos una interfaz de usuario simple además de eso.

En primer lugar, necesitamos un backend con soporte para API JSON. Debido a que este artículo está completamente dedicado al desarrollo front-end, preconstruí una fuente de datos disponible públicamente para que podamos centrarnos en nuestra aplicación web. Si estás interesado, puedes consultar el código fuente . Tenga en cuenta que muchas bibliotecas de implementación de API JSON están disponibles para todo tipo de pilas de tecnología, así que elija la que mejor se adapte a sus necesidades.

Mi servicio web de demostración nos plantea dos preguntas. La primera tiene dos respuestas y la segunda tres. La segunda respuesta a la primera pregunta tiene tres comentarios.

La salida del servicio web se convertirá a algo similar al ejemplo de Heroku después de que el usuario presione el botón y los datos se obtengan correctamente.

1. Descargue el texto estándar

Para reducir el tiempo de configuración de la aplicación web, he desarrollado un pequeño texto estándar de React que se puede utilizar como punto de partida.

Clonemos el repositorio.

git clone https://github.com/yury-dymov/json-api-react-redux-example.git --branch initial

Ahora tenemos lo siguiente:

  • Reaccionar y reaccionarDOM;
  • Redux y Redux DevTools;
  • paquete web;
  • ESLint;
  • Babel;
  • un punto de entrada a la aplicación, dos componentes simples, configuración ESLint, configuración Webpack e inicialización del almacén Redux;
  • definición de CSS para todos los componentes que vamos a desarrollar;

Todo debería funcionar desde el primer momento, sin que sea necesario realizar ninguna acción por tu parte.

Para iniciar la aplicación, escriba esto en la consola:

npm run webpack-dev-server

Luego, abra https://localhost:8050 en un navegador.

2. Integración de API

Comencemos por desarrollar middleware Redux que interactuará con la API. Usaremos json-api-normalizer aquí para cumplir con el principio de no repetirse (DRY); de lo contrario, tendríamos que usarlo una y otra vez en muchas acciones de Redux.

src/redux/middleware/api.js

import fetch from 'isomorphic-fetch';import normalize from 'json-api-normalizer';const API_ROOT = 'https://phoenix-json-api-example.herokuapp.com/api';export const API_DATA_REQUEST = 'API_DATA_REQUEST';export const API_DATA_SUCCESS = 'API_DATA_SUCCESS';export const API_DATA_FAILURE = 'API_DATA_FAILURE';function callApi(endpoint, options = {}) { const fullUrl = (endpoint.indexOf(API_ROOT) === -1) ? API_ROOT + endpoint : endpoint; return fetch(fullUrl, options) .then(response = response.json() .then((json) = { if (!response.ok) { return Promise.reject(json); } return Object.assign({}, normalize(json, { endpoint })); }), );}export const CALL_API = Symbol('Call API');export default function (store) { return function nxt(next) { return function call(action) { const callAPI = action[CALL_API]; if (typeof callAPI === 'undefined') { return next(action); } let { endpoint } = callAPI; const { options } = callAPI; if (typeof endpoint === 'function') { endpoint = endpoint(store.getState()); } if (typeof endpoint !== 'string') { throw new Error('Specify a string endpoint URL.'); } const actionWith = (data) = { const finalAction = Object.assign({}, action, data); delete finalAction[CALL_API]; return finalAction; }; next(actionWith({ type: API_DATA_REQUEST, endpoint })); return callApi(endpoint, options || {}) .then( response = next(actionWith({ response, type: API_DATA_SUCCESS, endpoint })), error = next(actionWith({ type: API_DATA_FAILURE, error: error.message || 'Something bad happened' })), ); }; };}

Una vez que los datos se devuelven desde la API y se analizan, podemos convertirlos a un formato compatible con Redux con json-api-normalizer y reenviarlos a las acciones de Redux.

 

Nota: este código se copió y pegó de una instancia de Redux del mundo real , con pequeños ajustes para agregar json-api-normalizer. Ahora puedes ver que la integración con json-api-normalizer es simple y directa.

src/redux/configureStore.js

Ajustemos la configuración de la tienda Redux:

+++ import api from './middleware/api';export default function (initialState = {}) { const store = createStore(rootReducer, initialState, compose(--- applyMiddleware(thunk),+++ applyMiddleware(thunk, api), DevTools.instrument(),

src/redux/acciones/post.js

Ahora podemos implementar nuestra primera acción, que solicitará datos del back-end:

import { CALL_API } from '../middleware/api';export function test() { return { [CALL_API]: { endpoint: '/test', }, };}

src/redux/reductores/data.js

Implementemos el reductor, que fusionará los datos proporcionados desde el back-end en la tienda Redux:

import merge from 'lodash/merge';import { API_DATA_REQUEST, API_DATA_SUCCESS } from '../middleware/api';const initialState = { meta: {},};export default function (state = initialState, action) { switch (action.type) { case API_DATA_SUCCESS: return merge( {}, state, merge({}, action.response, { meta: { [action.endpoint]: { loading: false } } }), ); case API_DATA_REQUEST: return merge({}, state, { meta: { [action.endpoint]: { loading: true } } }); default: return state; }}

src/redux/reductores/data.js

Ahora necesitamos agregar nuestro reductor al reductor raíz:

import { combineReducers } from 'redux';import data from './data';export default combineReducers({ data,});

src/components/Content.jsx

¡La capa del modelo está lista! Agreguemos el botón que activará la fetchDataacción y descargaremos algunos datos para nuestra aplicación.

 

import React, { PropTypes } from 'react';import { connect } from 'react-redux';import Button from 'react-bootstrap-button-loader';import { test } from '../../redux/actions/test';const propTypes = { dispatch: PropTypes.func.isRequired, loading: PropTypes.bool,};function Content({ loading = false, dispatch }) { function fetchData() { dispatch(test()); } return ( div Button loading={loading} onClick={() = { fetchData(); }}Fetch Data from API/Button /div );}Content.propTypes = propTypes;function mapStateToProps() { return {};}export default connect(mapStateToProps)(Content);

Abramos nuestra página en un navegador. Con la ayuda de las herramientas de desarrollo de nuestro navegador y Redux DevTools, podemos ver que la aplicación está obteniendo los datos del back-end en formato de documento JSON API, los convierte a una representación más adecuada y los almacena en la tienda Redux. ¡Excelente! Todo funciona como se esperaba. Entonces, agreguemos algunos componentes de la interfaz de usuario para visualizar los datos.

3. Obteniendo los datos de la tienda

El paquete redux-object convierte los datos del almacén Redux en un objeto JSON. Necesitamos pasar parte de la tienda, el tipo de objeto y el ID, y él se encargará del resto.

import build, { fetchFromMeta } from 'redux-object';console.log(build(state.data, 'post', '1')); // --- Post Object: { text: "I am fine", id: 1, author: @AuthorObject }console.log(fetchFromMeta(state.data, '/posts')); // --- array of posts

Todas las relaciones se representan como propiedades de objetos de JavaScript, con soporte de carga diferida. Por lo tanto, todos los objetos secundarios se cargarán sólo cuando sea necesario.

const post = build(state.data, 'post', '1'); // --- post object; `author` and `comments` properties are not loaded yetpost.author; // --- User Object: { name: "Alice", id: 1 }

Agreguemos varios componentes de la interfaz de usuario para visualizar los datos.

Normalmente, la estructura de componentes de React sigue el modelo de datos y nuestra aplicación no es una excepción.

src/components/Content.jsx

First, we need to fetch the data from the store and propogate it to the component via the connect function from react-redux:

import React, { PropTypes } from 'react';import { connect } from 'react-redux';import Button from 'react-bootstrap-button-loader';import build from 'redux-object';import { test } from '../../redux/actions/test';import Question from '../Question';const propTypes = { dispatch: PropTypes.func.isRequired, questions: PropTypes.array.isRequired, loading: PropTypes.bool,};function Content({ loading = false, dispatch, questions }) { function fetchData() { dispatch(test()); } const qWidgets = questions.map(q = Question key={q.id} question={q} /); return ( div Button loading={loading} onClick={() = { fetchData(); }}Fetch Data from API/Button {qWidgets} /div );}Content.propTypes = propTypes;function mapStateToProps(state) { if (state.data.meta['/test']) { const questions = (state.data.meta['/test'].data || []).map(object = build(state.data, 'question', object.id)); const loading = state.data.meta['/test'].loading; return { questions, loading }; } return { questions: [] };}export default connect(mapStateToProps)(Content);

We are fetching object IDs from the meta data of the API request with the /test endpoint, building JavaScript objects wi






Tal vez te puede interesar:

  1. ¿Deberían abrirse los enlaces en ventanas nuevas?
  2. 24 excelentes tutoriales de AJAX
  3. 70 técnicas nuevas y útiles de AJAX y JavaScript
  4. Más de 45 excelentes recursos y repositorios de fragmentos de código

json-api-normalizer: una forma sencilla de integrar la API JSON y Redux

json-api-normalizer: una forma sencilla de integrar la API JSON y Redux

Índice Trasfondo Mejores prácticas de Redux

programar

es

https://aprendeprogramando.es/static/images/programar-json-api-normalizer-una-forma-sencilla-de-integrar-la-api-json-y-redux-933-0.jpg

2024-05-20

 

json-api-normalizer: una forma sencilla de integrar la API JSON y Redux
json-api-normalizer: una forma sencilla de integrar la API JSON y Redux

 

 

Top 20