Pedro Fontes
Pedro Fontes

Reputation: 174

How to get value of `var` inside return of React component?

I'm trying to get the value of googleToken inside a <div> in the return of my React Component. The value is already updated, but it's the initial state here in the return, therefore, it always shows null

const Layout = props => {
 
  let googleToken = null;

  useEffect( () => {
    fetchGoogleToken();
  }, [])

  const fetchGoogleToken = async () => {
    await api
      .get("/google_token")
      .then((response) => {
        console.log('google_token: ' + response.data.google_token);
        googleToken = response.data.google_token;
        console.log('google_token updated: ' + googleToken);
      })
    .catch((error) => console.log(error));
  };

  const getGoogleToken = (res) => {
    
    console.log(res);
    setGoogleToken(res.accessToken);
    saveGoogleTokenInDB();
    
  };

  const saveGoogleTokenInDB = async () => {
    await api
      .post("/fit-auth", {google_token : googleToken})
      .then((response) => {
        console.log(response);
      })
    .catch((error) => console.log(error));
  };

return (       
  <div className={classes.googleButton} style={{display: googleToken === null ? 'block' : 'none'}}>
    <h3>{googleToken}</h3>
  <div/>
}

Any ideas on why I can't get the updated value?

Upvotes: 0

Views: 217

Answers (2)

Tarukami
Tarukami

Reputation: 1160

It is right to use useEffect hook for fetching. But the result must be kept into state. And when you ask react to update state, you can not watch changes on the next line of code using console.log because setState is async function and it will be executed later on.

  // this will never work as you might be expected:
  setState(newState)
  console.log(state)

To catch state updates always use useEffect hook as in example below:

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

Also, avoid using inline styles for showing / hiding your components. Check the official conditional rendering recommendations. The final code is going to look like this:

const Layout = props => {
  const [googleToken, setGoogleToken] = useState(null)

  useEffect( () => {
    fetchGoogleToken();
  }, [])

  // you can watch how state changes only using useEffect:
  useEffect(() => {
    console.log('google_token updated: ' + googleToken)
  }, [googleToken])

  const fetchGoogleToken = async () => {
    await api
      .get("/google_token")
      .then((response) => {
        console.log('google_token: ' + response.data.google_token);
        setGoogleToken(response.data.google_token);
      })
    .catch((error) => console.log(error));
  };

  // conditional rendering:
  if (!googleToken) return <span>Fetching token...</span>
  return (
    <div className={classes.googleButton}>
      <h3>{googleToken}</h3>
    <div/>
  )
}

Hope you will find this helpful.

Upvotes: 1

Vishal
Vishal

Reputation: 1

The issue is that when the value of googleToken is updated the component is not notified about this. Since the component is not notified about the change it still believes that the value is still the initial value and it does need to change anything in DOM.

To solve this issue try using states or just force a rerender once the function is executed.

Upvotes: 0

Related Questions