Callback function expressions passed as parameters using hooks

The more parent-child components we build, the more complex parameters become. One of these parameters is the callback functions that use the hook, useState that sets values within an object.

Richard Soriano
2 min readJul 30, 2021
Photo by Dragon Pan on Unsplash

Passing data is unidirectional. The child cannot pass data to the parent; therefore, the parent must pass references of functions to the child in order for the values to be available in the parent.

In this example we will use the hook, useState to set a form value and create a controlled component.

const [ name, setName ] = useState("")
/* Parent */
<TextField
onChange = {(val) => setName(val) }
/* Child component */
export default function TextField () {
return (<input
type=”text”
name=”name”
onChange = { e => onChange( e.target.value) }

Refactoring so the hook and child component are reusable

Creating an object to represent the form and each key in the object holds the value of each field in the form. So if you’re doing a simple login form with name and email:

formValues now has the default values of the form. In useState the default values are always used.

const formValues = { 
name: '',
email: '',}
const [formValues, setFormValues ] = useState( formValues )
/* Parent */
<TextField
onChange={ (val ) => setFormValues(name: val.name )} />

You would think that you would be able to do something like that. Keep in mind that the state is immutable meaning, you can not setState values directly. You have to copy them over. The previous data must also be preserved that’s why we use prev and the spread operator. We return an object.

/* Parent */
<TextField
onChange={ (val ) => setFormValues( (prev) => ({
...prev,
name: val.name})
/>

Closure

Here is a great example of using hoisting. Closure is protecting the scope of a variable, name. This is especially precarious since you have an arrow function within an arrow function. The best way to protect it is to set it to a constant right away so it doesn’t get overwritten.

Since name: name is the same as name in ES6.

/* Parent */
<TextField
onChange={ (val ) =>
const name = val.name
setFormValues( (prev) => ({
...prev,
name,
})
/>
/* Child */
export default function TextField () {
return (<input
type=”text”
name=”first”
onChange = {
e => onChange(e.target.value)
})} />)

Credit to Devmentorlive for a terrific youtube example, A React JS Text Field with Validations using Hooks, of creating your own form fields that are reusable components with validations.

Learn More

useState and callback functions https://www.robinwieruch.de/react-usestate-callback

https://reactjs.org/docs/faq-functions.html

--

--

Richard Soriano

Passion for Web Developing. Specializing in Front-End such as React, Redux and expanding to the Back-End with NodeJS to MongoDB and GraphQL