Part of every developers dilemma is deciding which approach to take in addressing certain problems. Genuine solutions require a certain amount of effort and steps to achieve and there exists acceptable “workarounds” that tests every developers way of thinking.
Here are some simple workarounds that you might find helpful and will help save time in cases you still haven’t figured out the right solution.
For you to follow along and experiment your use-cases or check the results yourself, here’s a quick guide.
npx create-react-app my-app
cd my-app
npm start
Optional
Install your favorite UI library (in this example, I used ant-design).
1. Force re-render by updating component key property
There might be instances that you need to reset your component state (e.g. form states) after a certain action (click event, keyboard event, after certain requests, you name them…) outside your form component, and realized you don’t have access to the form library’s reset function.
Form component (use your favorite form state library, react-hook-form in this example)
import React from 'react'
import { Form, Input } from 'antd'
import { useForm, Controller } from 'react-hook-form'
const FormComponent = () => {
const { control, getValues } = useForm();
const formValues = getValues()
return (
<Form>
<Controller
name="firstname"
control={control}
defaultValue={formValues.firstname}
render={props => <Input {...props} placeholder="First name" />}
/>
<Controller
name="lastname"
control={control}
defaultValue={formValues.lastname}
render={props => <Input {...props} placeholder="Last name" />}
/>
</Form>
)
}
Usage
import React, { useState } from 'react'
import { Button } from 'antd'
// use your favorite library (e.g. uuid)
const getUniqueFormKey = () => (new Date()).toISOString()
export default () => {
const [key, setKey] = useState(getUniqueFormKey())
return (
<div>
<FormComponent key={key} />
<Button onClick={() => setKey(getUniqueFormKey())}>Reset form</Button>
</div>
);
}
Result
By changing the components key
property, we were able to re-render the component completely and reset its state
2. Access react state in event listeners via useRef
There might be cases that you’ll need to add an event listener, override specific key binding, access react state from useState
and trigger certain actions from there.
Sounds easy, right? It feels natural, but your state will most probably be empty. Let’s try.
Component
import React, { useState } from 'react'
import { Input } from 'antd'
const App = () => {
const [formState, setFormState] = useState({ fname: '', lname: '' })
return (
<div>
<Input
value={formState.fname}
placeholder="First name"
onChange={e => setFormState({
...formState,
fname: e.target.value,
})}
/>
<Input
value={formState.lname}
placeholder="Last name"
onChange={e => setFormState({
...formState,
lname: e.target.value,
})}
/>
</div>
);
}
Then add keydown
event listener via useEffect
import React, { useEffect } from 'react'
import { Input } from 'antd'
const App = () => {
...
useEffect(() => {
const onKeydown = e => {
if (e.code === 'Enter') {
// do whatever you want with the state
console.log(formState)
}
}
if (window) window.addEventListener('keydown', onKeydown)
return () => {
if (window) window.removeEventListener('keydown', onKeydown)
}
}, [])
...
}
With this setup, this is what the state looks like upon triggering the “Enter” key from the keyboard, it doesn’t contain anything but the default values.
To access the updated state in the event listener, add the following modifications to the code
- Import
useRef
and set the default value with the state’s value - Add another
useEffect
that will keep theformStateRef
value updated every time the state changes - Use the
formStateRef.current
on theonKeydown
instead
import React, { useEffect, useRef } from 'react'
import { Input } from 'antd'
const App = () => {
const [formState, setFormState] = useState({ fname: '', lname: '' })
const formStateRef = useRef(formState)
useEffect(() => {
const onKeydown = e => {
if (e.code === 'Enter') {
// do whatever you want with the state
console.log(formStateRef.current)
}
}
if (window) window.addEventListener('keydown', onKeydown)
return () => {
if (window) window.removeEventListener('keydown', onKeydown)
}
}, [])
useEffect(() => {
formStateRef.current = formState
}, [formState])
...
}
Result
And we can now have access to the updated state via useRef in our event listener.
It’s good to note that the above workarounds will work on any stateful components, and are not limited to form components.
Conclusion
While it is always good to find a genuine solution to a problem, workarounds can be as creative as true solutions and I find some of them saving me from doing over-engineered solutions which convolute the codebase unnecessarily. Plus, it saves time!
More from
Engineering
Importance of Design QA workflow
Marvin Fernandez, Engineering Manager
SQA questions to ponder
Joy Mesina, QA
Writing a Software Test Plan
Ron Labra, Software Quality Analyst