Source: templates/ForEach.js

import React, { useEffect, useMemo, useState } from "react";
import { useSelector } from "react-redux";
import { booleanString, emptyObject, processIncludeVariables, processOptions, Template, useIncludeVariables } from "../..";
const objectPath = require("object-path");

/**
 * Componente que convierte variable lista en una lista de componentes
 * @name Reactor.Components.Templates.ForEach
 * @param {string} variable Nombre de la variable
 * @param {string} [context = "global"] Nombre del contexto a usar
 * @param {string} template 
 * Un nombre de template o un html template, el template va a recibir las propiedades de cada objeto como parametros, 
 * y aparte como parametros especiales va a recibir {{index}}, {{_variable}} y {{_context}}
 * @param {string} empty Un nombre de template que se ejecuta cuando el array es nulo o no tiene elementos
 * @param {JsonString} [params = "{}"] Parametros que se envian a cada item y se inyectan en el objeto
 * @param {string} [include_variables = ""] Lista de variables que se envian a cada item en la propiedad _includeVariables
 * @class 
 * @example 
<ul>
  <!--en el template las propiedades del item pasan como parametros-->
  <for_each variable="lista" context="un_contexto" template="NombreTemplateItem" empty="NombreTemplateVacio">
  </for_each>
</ul>
 */

export const ForEach = ({variable, context = "global", template, empty, children, params, include_variables, debug = "false"}) => {
 
  const varsContext = useSelector(state => state.app.variables[context])
  const list = useMemo(() => objectPath.get( varsContext, variable), [varsContext, variable]);
  const _includeVariables = useIncludeVariables({variablesState: varsContext, include_variables});
  const paramsObj = useMemo(() => processOptions(params, emptyObject, emptyObject), [params]);

  const result = useMemo(() => {
    booleanString(debug) && console.log({list, variable, context, _includeVariables})    
    const data = (list && list.length > 0)
      ? list.map((item, index) => {
        const content = typeof item === "object" 
          ? {...item || emptyObject, template, ...paramsObj, index, _context: context, _variable: variable, _includeVariables: _includeVariables?.variables}
          : {item, template, ...paramsObj, index, _context: context, _variable: variable, _includeVariables: _includeVariables?.variables};
        booleanString(debug) && console.log({content})
        return <Template key={item.key} content={content} />
      })
      : (empty && <Template content={{template: empty}} />);
    return data;
  }, [empty, list, template, paramsObj, variable, context, debug, _includeVariables]);  

  return (
    <>
      <>
        {result}
      </>
      {children}
    </>
  );

}