0

So, the request is returning the JSON file. But when in console it is saying 'Undefined' and I do not know why.

So the button when clicked will send the results from my request from the google Place API; which contains the place_id needed to make the call to the Place Details API to the Info component.

const OnButtonClick = (restaurant) => {
        setRestaurant(restaurant)
        setOpenPopup(true)
    }
<button className="cardButton" onClick={() => OnButtonClick(restaurantData)}>
    View Information
</button>
<InfoPopup open={openPopup} restaurant={restaurant} onClose={() => setOpenPopup(false)} />

So, this works the way I think it does (Sorry, I am new to React)

Here's the InfoPopup component

function InfoPopup({ open, onClose, restaurant }) { 
    const [restaurant1, setRestaurant1] = useState([])

    let id = restaurant.place_id
    let URL = `/maps/api/place/details/json?place_id=${id}&key=${process.env.REACT_APP_API_KEY}`
    const fetchRestaurants1 = async () => {
        const res1 = await axios.get(URL)
        setRestaurant1(res1.data.results);
      }

    useEffect(() => {
          fetchRestaurants1()
          console.log(restaurant1) //This is getting 'Undefined' 
      }, [id]);
        

    const navigate = useNavigate()
    if (!open) {return null}
   

    return ReactDOM.createPortal(
    <>
        <div>
            {restaurant1?.map(restaurant => (
                <div key={restaurant.place_id}> {restaurant.formatted_phone_number} </div>
            ))}
        </div>
        <div className="popup">
            <div className="popup-inner">
                <button className="close-btn" onClick={onClose}> Close </button>
                <h1 className="title"> {restaurant.name} </h1>
            <ul>
                {/* <li className="service">
                    Status: {}
                </li> */}
                <li className="location">
                    Address: {restaurant.vicinity}
                    Phone Number: 
                </li>
                <li className="cost">
                    Cost: {restaurant.price_level}
                </li>
                {/* <li className="food">
                    Food Type:
                </li> */}
            </ul>
            <div className="links">
                <Link className="writeButton" to="/write" state={{data: restaurant}}>
                    Write a review
                </Link>
                {/* <button className="writeButton" onClick={() => navigate("/write", {data:restaurant})}>
                    Write a review
                </button> */}
                <Link className="readButton" to="/read" state={{data: restaurant}}>
                    Read the reviews
                </Link>
                {/* <button className="readButton" onClick={() => navigate("/read")}>
                    Read the reviews
                </button> */}
            </div>
            </div>
        </div>
    </>,
    document.getElementById('portal')
  )
}

I think the problem is on the first render, there's no ID being passed. But I do not know how to work around it. Any help would be appreciated.

John
  • 1
  • If you suspect the first render is the issue can you simply just make a if/else statement to handle the first render in the if and then let the rest default to the else? – boredProjects Nov 18 '22 at 20:25
  • I tired that, but I get "React Hook "useEffect" is called conditionally." and "React Hook "useNavigate" is called conditionally." Maybe I am doing the if else wrong – John Nov 18 '22 at 20:32
  • Hmm is it possible for you to catch the id inside the useEffect? So instead of placing the if outside of useEffect its inside and will detect if the id is null or not? – boredProjects Nov 18 '22 at 20:38
  • 1
    `fetchRestaurants1` is async but you're not waiting for it to finish in the `useEffect` call. Also react state updates a async also so you won't be able to see the updated value of `restaurant1` in that same `useEffect` anyway. Log `restaurant1` in the main body of the component and you'll see the value – Henry Woody Nov 18 '22 at 20:42
  • @boredProjects I have also tired that haha – John Nov 18 '22 at 20:50
  • @HenryWoody, sorry but I am not following. Could you show it? – John Nov 18 '22 at 20:50
  • Does this answer your question? [React setState not updating state](https://stackoverflow.com/questions/41446560/react-setstate-not-updating-state) – Henry Woody Nov 18 '22 at 22:39
  • I am getting this new error unfortunately: InfoPopup.js:59 Uncaught TypeError: restaurant1.map is not a function – John Nov 18 '22 at 23:18

1 Answers1

0

Looking at this block of code:

 const fetchRestaurants1 = async () => {
    const res1 = await axios.get(URL)
    setRestaurant1(res1.data.results);
  }

useEffect(() => {
      fetchRestaurants1()
      console.log(restaurant1) //This is getting 'Undefined' 
  }, [id]);

You're awaiting the result of the GET call, which is good, because it allows you to set state in the next line after waiting for the response.

The problem: when you call fetchRestaurants1() in the useEffect(), you're not waiting for that function to execute, therefore, we jump straight to the next line and console.log() restaurant1, which is of course still blank.

The same issue arises with set state calls. If you do:

const [value, setValue] = useState(null);

then sometime later:

setValue(5);
console.log(value);

The value posted to console will be null, because JS doesn't want to wait for the set state call to finish before moving onto the next line, console.log(value);

To fix this: make the useEffect callback async, and await the functions in which you're making your axios.get calls. Example:

  const fetchSomeData = async () => {
    const response = await axios.get(URL);
    setData(response.data);
  }

  useEffect(async () => {
      await fetchSomeData();
      /* do some stuff */
  }, []);

Of course, you still can't console.log after the set state call above.

If you want a generalizable way to log state changes without worrying about async behavior, you can add a simple useEffect:

  useEffect(() => {
    console.log(value);
  }, [value]);

Where value is any state variable. Since value is in the dependency array, anytime it changes, the useEffect will fire and log the change.

  • Thanks. But now I can't get the object array back. When the button is clicked, the place_id gets passed and the request was made, but the array returned is empty/undefined. – John Nov 18 '22 at 21:29