Keep components readable, put handlers after jsx
β2 min read
- hoisting
- code-organization
- React 18
The problem
Ui devs are used to writing handlers and components.
Ideally those should be understandable at a first glance.
I'd argue that library hooks and jsx are the most important bits. Thus should be kept at the top and easily accessible.
The answer
Use function declaration syntax and its' hoisting functionality to move repetitive handler logic below jsx and library core functions invocations.
Write like this π
import { ChangeEvent, FormEvent, Fragment, useId, useState } from "react";
import { v4 as uuidv4 } from "uuid";
import "./App.css";
type UserData = {
name: string;
age: string;
uuid: string;
};
function App() {
const [users, setUsers] = useState([]);
const [name, setName] = useState("");
const [age, setAge] = useState("");
// let's use React 18's useId hook;
const nameInputId = useId();
const ageInputId = useId();
return (
{/* remember that 0 && true will return literally zero ("0") */}
{/* is a renderable ReactNode unlike false!!! */}
{/* let's coerce length to boolean to avoid it */}
{!!users.length && (
saved users
{users.map((dr) => (
-
{`${dr.name} - ${dr.age}`}{" "}
))}
)}
);
function handleSubmitUser(event: FormEvent) {
event.preventDefault();
const newUser = { name, age, uuid: uuidv4() } satisfies UserData;
setUsers(users.concat(newUser));
handleClearForm();
}
function handleClearForm() {
setName("");
setAge("");
}
function handleRemoveUser(uuid: string) {
setUsers(users.filter((user) => user.uuid !== uuid));
}
function handleNameInputChange(e: ChangeEvent) {
setName(e.target.value);
}
function handleAgeInputChange(e: ChangeEvent) {
setAge(e.target.value);
}
}
export default App;
instead of this π₯Ίπ₯β€οΈβπ©Ή
import { ChangeEvent, FormEvent, Fragment, useId, useState } from "react";
import { v4 as uuidv4 } from "uuid";
import "./App.css";
type UserData = {
name: string;
age: string;
uuid: string;
};
function App() {
const [users, setUsers] = useState([]);
const [name, setName] = useState("");
const [age, setAge] = useState("");
// most likely when the component grows you will have to scroll
// a bunch of lines to get to the jsx
// let's use React 18's useId hook;
const nameInputId = useId();
const ageInputId = useId();
function handleSubmitUser(event: FormEvent) {
event.preventDefault();
const newUser = { name, age, uuid: uuidv4() } satisfies UserData;
setUsers(users.concat(newUser));
handleClearForm();
}
function handleClearForm() {
setName("");
setAge("");
}
function handleRemoveUser(uuid: string) {
setUsers(users.filter((user) => user.uuid !== uuid));
}
function handleNameInputChange(e: ChangeEvent) {
setName(e.target.value);
}
function handleAgeInputChange(e: ChangeEvent) {
setAge(e.target.value);
}
/* remember that 0 && true will return literally zero ("0") */
/* is a renderable ReactNode unlike false!!! */
/* let's coerce length to boolean to avoid it */
return (
{!!users.length && (
saved users
{users.map((dr) => (
-
{`${dr.name} - ${dr.age}`}{" "}
))}
)}
);
}
export default App;
Summary
Javascript's hoisting feature doesn't get the love it deserves. Try out the strategy i've described. You might end up sticking with it π .