ErDevFy
ErDevFy

Reputation: 105

Data renders twice with different output

I am using Reactjs. When I console log randomData I expect the output to be a random text from the data and then I want to loop over it. But the result is strange and getting 2 different outputs for each log. When I am out of the useEffect I can't even Array.prototype.map() over randomData or use String.prototype.split(""). PS: I know that If I log inside the useEffect it will only render once, but How I get the data(each text) out of the useEffect then I can use it to loop over?

source: https://codesandbox.io/s/react-playground-forked-3bd7z

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

function App() {
  const data = [
    {
      id: 1,
      text: "hello world"
    },
    {
      id: 2,
      text: "hi world"
    },
    {
      id: 3,
      text: "hola"
    },
    {
      id: 4,
      text: "oo"
    }
  ];

  const [randomData, setRandomData] = useState(data);

  useEffect(() => {
    let randomIndex = Math.floor(Math.random() * randomData.length);
    setRandomData(randomData[randomIndex].text);
  }, []);

  console.log(randomData);

  console.log(typeof randomData);

  return (
    <div className="App">
      {/* {data.map(item => console.log((item.text).split("").map(letter => letter)))} */}
      {/* {console.log(typeof randomData)} */}
    </div>
  );
}

useEffect issue

Upvotes: 0

Views: 227

Answers (1)

Taxel
Taxel

Reputation: 4207

Your problem with the duplicate output is because you are assigning the data to randomData initially. React then rerenders (yielding the first console output) and only then calls your useEffect hook.

I would propose you don't use useEffect at all but instead an initialization function for useState:

const [randomData, setRandomData] = useState(()=>{
    let randomIndex = Math.floor(Math.random() * data.length);
    return data[randomIndex].text;
  });

This way the data is set during the first render, not after it.

EDIT: If the data is coming from an external api, useEffect is the right choice. In that case you start fetching in useEffect and then set the state once you have the data. Initialize the state to your preferences, (I'd go with useState(null)) and handle your render accordingly, because until you have data, randomData will not contain anything.

Upvotes: 2

Related Questions