Tengo un componente de reacción (escrito con Typescript) como se muestra a continuación.
En este componente, trato de leer el Excel en el que tengo los datos y luego uso los datos para representar el componente.
Dado que los datos no se leen antes de ejecutar useEffect , menuData se inicializa como null .
Leer los datos funciona bien y no tengo ningún error con menuData.
Sin embargo, la línea let meals = [...new Set(menuData.map((item: menuItem) => item.Meal))]; está arrojando el error TypeError: menuData is undefined . Creo que esto se debe a que esta línea se ejecuta cuando menuData aún no está undefined (antes de que se ejecute useEffect).
¿Cómo superar este error? En otras palabras, cómo ejecutar let meals = [...new Set(menuData.map((item: menuItem) => item.Meal))]; DESPUÉS de que useEffect se haya ejecutado?
Me gustaría mantener esta línea fuera de useEffect porque hay muchas más funciones de matriz (mapa, filtro, etc.) que deben realizarse en la matriz de objetos menuData.
export const CategoryItems = ({ toggled }: CategoryItemsProps) => { const [menuData, setMenuData] = useState<menuData | undefined>(undefined); /*Code to read the excel with menu items once the page is loaded. The sheet will be read only once*/ useEffect(() => { let url = "data.xlsx"; ........ .... ..... setMenuData(XLSX.utils.sheet_to_json(worksheet, { raw: true })); }, []); let meals = [...new Set(menuData.map((item: menuItem) => item.Meal))]; return ( <div className={`category-items ${toggled ? "theme-dark" : "theme-light"}`}> . . . //additional code to render the component based on the variable `meals` . . . </div> </div> ); };Simplemente inicialice su estado como una matriz vacía ya.
const [menuData, setMenuData] = useState<menuData>([]);¡Eso debería funcionar!
Personalmente, me gusta salir de la etapa de renderizado si los datos aún no han llegado, no tiene sentido ir más allá ya que setState dentro de useEffect va a causar otro renderizado de todos modos.
if (!menuData) return null; let meals = [...new Set(menuData.map((item: menuItem) => item.Meal))]; null es solo una forma simple de renderizar nada ...
Lo que me gusta de esta forma de hacerlo es que, si encuentra que useEffect a veces puede llevar algo de tiempo, en lugar de devolver null , tal vez podamos devolver algún tipo de indicador de carga.
if (!menuData) return <div className="loading">Loading..</div>; let meals = [...new Set(menuData.map((item: menuItem) => item.Meal))];La inicialización de los datos en algo vacío funciona, pero se pierde algo de estado implícito, y si las estructuras de su renderizado son más complejas, resulta mucho más fácil razonar con salir temprano.