2
votes

I'm trying to learn how React hooks work with a simple authentication modal that I've set up. I have a custom useForm hook that handles form state, and I'm curious as to how I have access to values before it's declared.

function LoginModal () {
   console.log('outside values', values) // undefined
   const submitForm = async () => {
     console.log('inside values', values) // email, password values exist
     const request = {
        method: 'POST',
        url: '/auth/login',
        data: {
           email: values.email,
           password: values.password
        }
    }
    await axios(request)
  }

  const [values, handleChange, handleSubmit] = useForm(submitForm)

  return <div>some form stuff</div>
}

`useForm.js`

import { useState } from 'react'

const useForm = submitForm => {
  const [state, setState] = useState({})

  const handleChange = event => {
    event.persist()
    setState(state => ({ ...state, [event.target.name]: event.target.value }))
  }

  const handleSubmit = event => {
    event.preventDefault()
    submitForm()
  }

  return [state, handleChange, handleSubmit]
}

export default useForm


Can someone explain to me why values exist only within the submitForm function, and how it's available before const [values] is even declared? I believe const declarations aren't hoisted. Thanks!

1

1 Answers

2
votes

When you declare a function JS will keep that function declaration in memory and will give access the its respective local and global scope. This is what happens to your submitForm function. In the example from the snippet below, this is the someFunc function.

As you can see form the example below, if you execute that function before the variable values has been declared, you'll get undefined. Because it's not in scope yet.

But if you execute the function through a click event like you're doing, after the variable values has been defined, your function will be able to 'see' the variable because it's already in scope.

NOTE: You're correct. const declarations are not hoisted.

function App() {
  
  // WHEN YOU CALL IT THROUGH A CLICK EVENT, THE VARIABLE `values` WILL BE IN SCOPE
  function someFunc() {
    console.log('State from someFunc(): ' + values);
  }
  
  console.log('State from component body BEFORE variable "values" declaration: ' + values);
  
  someFunc(); // WHEN EXECUTED AT THIS POINT. IT HAS NO ACCESS TO 'values' BECAUSE IT'S STILL undefined
  
  const [values,setValues] = React.useState(['a','b','c']);
  
  console.log('State from component body AFTER variable "values" declaration: ' + values);
  
  return(
    <button onClick={someFunc}>Click to run someFunc()</button>
  );
}

ReactDOM.render(<App/>,document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>