Tengo un componente que contiene datos de un punto final. Muestro una ruleta mientras los datos aún no estén listos.

const UserName = () => {
  const {data: user, isLoading} = Client.query('user')
  return (
    <div>
      {
        isLoading
        ?
        <Spinner />
        :
        <div>
          {user.name}
        </div>
      }
    </div>
  );
}

Esto funcionaba bien como estaba. Sin embargo, quería extraer esta lógica en un componente separado para compartir el comportamiento de todo el contenido descargado. Y para que todos los hiladores siempre se vean iguales

Intenté hacer lo siguiente:

const DynamicContent = ({isLoading, children}) => {
  if(isLoading){
    return <Spinner />
  } else {
    return children
  }
}

const UserName = () => {
  const {data: user, isLoading} = Client.query('user')
  return (
    <DynamicContent isLoading={isLoading}>
        <div>
          {user.name}
        </div>
    </DynamicContent>
  );
}

Ahora esto no funciona porque el usuario no se ha definido cuando el componente se procesa por primera vez, así que obtengo un puntero nulo en user.name.

Sospecho que esto sucede porque el contenido que se pasa como hijos a mi DynamicContent se calcula primero.

¿Cómo haría para procesar condicionalmente el contenido pasado como hijos? ¿Hay alguna manera de hacer la evaluación que los niños pasaron al componente perezoso?

EDITAR: Establecer un valor predeterminado para el usuario no es una opción en mi caso real porque el objeto devuelto desde el punto final es un objeto profundamente anidado en el que accedería a atributos como user.x.y.z.

Podría agregar nullchecks en todas partes donde se accede a un atributo del usuario, pero esto se vuelve feo rápidamente.

Estoy buscando una forma que me permita interpretar perezosamente el contenido del componente secundario al pasarlo al DynamicContent. Algo en la línea de:

const UserName = () => {
  const {data: user, isLoading} = Client.query('user')
  return (
    <DynamicContent isLoading={isLoading}>
        <Lazy>
          <div>
            {user.address.country.name}
          </div>
        </Lazy>
    </DynamicContent>
  );
}

0
Enermis 3 jun. 2020 a las 17:20

3 respuestas

La mejor respuesta

La forma más fácil de dar a user un valor vacío predeterminado como:

const UserName = () => {
  const {data: user = {}, isLoading} = Client.query('user')
  return (
   <DynamicContent isLoading={isLoading}>
     <div>
      {user.name}
     </div>
   </DynamicContent>
  );
}

El valor se anulará cuando la API devuelva al usuario.

Otra forma puede ser verificar si el objeto no es nulo antes de acceder a los valores desde él.

typescript hacerlo usando como user?.name lodash tiene una utilidad similar get de un objeto si está presente.

O siempre puede enderezar su propia utilidad para lo mismo.

1
Vishal Sharma 3 jun. 2020 a las 14:57

Intenta así ... espero que te ayude a entender el camino.

export default function UserName(){
  let user = {
    name: 'John'
  }
  return (
    <DynamicContent isLoading={true}>
        <div>
         <h1>Hello {user.name}</h1>
        </div>
    </DynamicContent>
  );
}
const DynamicContent = ({isLoading, children}) => {
  if(isLoading){
    return <Spinner />
  } else {
    return children
  }
}
const Spinner = () => <h3>Loading...</h3>

Pasé fiel a isLoading. puede intentar poner su condición requerida.

Demo en vivo

0
Vahid Akhtar 3 jun. 2020 a las 14:38

Esto podría darle más claridad sobre cómo puede usarlo

import React, { useState, useEffect } from "react";
import "./styles.css";

export default function UserName() {
  const [user] = useState({
    name:'John'
  })
  const [isLoading,setisLoading] = useState(true)

  useEffect(()=>{
    setTimeout(()=>{
      setisLoading(false)
    },3000)
  },[])

  return (
    <DynamicContent isLoading={isLoading}>
      <div>
        <h1>Hello {user.name}</h1>
      </div>
    </DynamicContent>
  );
}
const DynamicContent = ({ isLoading, children }) => {
  if (isLoading) {
    return <Spinner />;
  } else {
    return children;
  }
};
const Spinner = () => <h3>Loading...</h3>;

Aquí está la demostración de trabajo: -

0
Rohan Naik 3 jun. 2020 a las 15:14