Home > database >  After Promise object not rendering
After Promise object not rendering

Time:04-25

I have been trying to display map an array after resolving its promise. Unfortunately, it is not being rendered. Here is the code:

<View>
     {array.map((item) => {
        promiseFunction(item).then((res) => {
          return (
            <FunctionalComponent
             prop={res.prop}
            />
          );
        });
      })}
</View>

CodePudding user response:

You have to separate the async function from rendering. And you have to do the array.map properly. The list of FunctionalComponent props must be a state.

const [propsArray, setPropsArray] = useState([])

useEffect(() => {    // or any other function, that will feed data
    array.map(item => {
         promiseFunction(item).then(res => {
                setPropsArray(p => [...p, res])
         }
    }, 
[])

return (<View>
 {propsArray.map(c => (<FunctionalComponent prop={c.prop} />) }
</View>)

CodePudding user response:

Array.prototype.map() won't wait for Promise to resolve, so data will never be rendered. You should try classic for ... of.

const Foo = ({}) => {
  const [components, setComponents] = useState([])

  useEffect(() => {
    (async () => {
      for (const item of array) {
        setComponents([...conponents, <FunctionalComponent prop={(await promiseFunction(item)).prop}/>])
      }
    })()
  }

  return (
   <View>
     {components}
   </View> 
  )
}

CodePudding user response:

You can't do that directly as you are trying to since React will try to render an array of promises and when they have resolved it's too late the Component has already rendered. Previous answers showd you how to set to state the results once they come and render only after the promises are fulfilled. But with React@18 you could jump that step and render the promises almost directly. If you are using Suspense, there is a way to handle this kind of scenarios, because Suspended components are able to consume promises directly and to render a fallback until they resolve:

const arr = [1, 2, 3, 4, 5];

export default function App() {
  return (
    <Suspense fallback={<p>Loading.....</p>}>
      <AsyncComponent />
    </Suspense>
  );
}

export const AsyncComponent = () => {
  // THIS IS AN ARRAY OF PROMISES

  const data = arr.map((el, i) => {
    const d = useGetData(`https://jsonplaceholder.typicode.com/todos/${i   1}`);
    console.log(d);
    return (
      <h5>
        {i   1}:{d?.title}
      </h5>
    );
  });
  // HERE YOU RENDER THE PROMISES DIRECTLY
  return <div>{data}</div>;
};

A demo that you can play with, HERE.

  • Related