1

there is an array that displays the data by the number of elements, every time the callapi receives the type as blob, passes it through the fileReader and returns the data to render the component but the data is not displayed

export default function App() {
  const arr = [
    { name: "A", id: 1 },
    { name: "B", id: 2 },
    { name: "C", id: 3 }
  ];

  const Render = () => {
    return arr.map((item) => {
      const fetchAttachment = async () => {
        try {
          const res = await axios.get(`apiURL/${item.id}`, {
            responseType: "blob",
            headers: defaultHeader
          });

          let reader = new window.FileReader();
          reader.readAsDataURL(res.data);
          reader.onload = () => {
            let link = reader.result;
            return link;
          };
        } catch (error) {
          console.log(error);
        }
      };
      const linkview = fetchAttachment();

      return <Item linkview={linkview} />;
    });
  };

  return (
    <div className="App">
      <Render />
    </div>
  );
}

export function Item({ linkview }) {
  return (
    <div>
      <p>{linkview}</p>
    </div>
  );
}
  • `fetchAttachment()` returns a promise but you're not `await` it. Because you can't render asynchronously then you'll need to save the result somewhere (`const [links, setLinks] = useState([]);` for example). The initial fetch could be done with `useEffect({ ...... }, []);` – Adriano Repetti May 15 '23 at 08:54
  • Can you give me an example to make it easier to understand? – phu.duongquoc May 15 '23 at 08:56
  • Random search result: https://stackoverflow.com/a/66507736/1207195. Note however that you're using `onload` wrongly: returning something won't make it the return value of the promise! Another random search result as starting point: https://stackoverflow.com/a/35718902/1207195 – Adriano Repetti May 15 '23 at 09:05
  • I can't use it in useEffect because I need the id value passed when calling the api, if I use it, I will have to map the array again. – phu.duongquoc May 15 '23 at 09:06
  • You surely can, if `arr` isn't constant then it'll simply be a dependency for `useEffect({ ...... }, [arr])`). Just remember to memoise/cache it or you'll refetch each time you re-render – Adriano Repetti May 15 '23 at 09:09
  • yes it is possible to use `useEffect` , but every time the `setState` is set, the `arr.map` to render the `Component ` will be called again and it will map the array again, not to mention the data may be out of place – phu.duongquoc May 15 '23 at 09:20
  • _"... but every time the setState is set, the arr.map to render the Component will be called again..."_. That's exactly what is expected (see also my comment about re-rendering). – Adriano Repetti May 15 '23 at 09:26
  • it worked but there is another problem as to why my axios already have async await but return value is not in the order it was called for example callapi 1 -> 2 -> 3 , return value is 2 -> 1 -> 3 – phu.duongquoc May 15 '23 at 09:53

1 Answers1

-1

There are some mistakes you are doing.

  1. You are not returning reader or reader results in the fetchAttachment() function.
  2. The fetchAttachment() is async function, so the data return from it is a pending promise. So, you can use .then() to get the data.
  3. You are rendering the ListView Component without providing key. Without key, you will get a warning like "Key should be provided for list items".
  4. One more thing, I notice, that you are using "apiURl" as a string in the axios request. I think it is a variable that has URL.

Here is the updated code. Try that:-

export default function App() {
  const arr = [
    { name: "A", id: 1 },
    { name: "B", id: 2 },
    { name: "C", id: 3 }
  ];

  const Render = () => {
    return arr.map((item, index) => {
      const fetchAttachment = async () => {
        try {
          const res = await axios.get(`${apiURL}/${item.id}`, {
            responseType: "blob",
            headers: defaultHeader
          });

          let reader = new window.FileReader();
          reader.readAsDataURL(res.data);
          reader.onload = () => {
            let link = reader.result;
            return link;
          };

          // Return the result of reader
          return reader.result;
        } catch (error) {
          console.log(error);
        }
      };

      // As the function retrun a promise, use then() to get the value
      fetchAttachment(index).then((linkview) => {
        console.log(linkview);
        return <Item key={index} linkview={linkview} />;
      });
    });
  };

  return (
    <div className="App">
      <Render />
    </div>
  );
}

export function Item({ linkview }) {
  return (
    <div>
      <p>{linkview}</p>
    </div>
  );
}

Hope it will be helpful.

Developer
  • 1,297
  • 1
  • 4
  • 15