The JavaScript community has designated certain syntax and features in the JavaScript language as the "bad parts of the language" because of their quirks, security concerns, or redundancy.
However, React, a JavaScript UI libraty, supports some of these quiky features and advocates declarative programming over imperative programming, the implementation of a virtual DOM, no separation of concerns, and a single source of truth. (state)
Here are some:
1. Double negation short hand.
Double negation is a Boolean constructor's double negation, indicated by !! (2 exclamation points), provides a shortcut for determining if a value is true or false. Eslint frowns upon double negation because it is redundant, and some people say it is unreadable.
In Javascript, there are 9 falsy values in javascript namely:
null, undefined, NaN,0,-0,
(empty template strings),false, [] “”, '', (single and double empty string)
Usage:
const posts=[];
let username=""; // empty string is falsy value
username=prompt("Enter your user name")
// username will either be undefined or empty string if someone doesn’t add there name.
if(!!username)
console.log(`Welcome ${username}`)
else
console.log(`Name not added`);
if(!!posts)
console.log(` ${posts.length} posts found`)
else
console.log(`There are no posts`)
// To negate a value use a third exclamation mark;
const isOnline=true;
if(!!!isOnline)
console.log("You are currently offline")
else
console.log("Your are currently online")
// in React, we use double negation in JSX as such;
const [posts,setPosts]=React.useState([]);
// we’re expecting a user object from,say, backend asynchronousrequest
const [user,setUser]=React.useState(null)
<ul>
{!!posts.length ? Posts.map(post=><li key={post.id}>{post.title}</li>)}
</ul>
<div>
<h5>{!!user ? user?.name : ""}</h5>
<p>{!!user ? user?.title : ""} </p>
</div>
2. Console.hell
Console.log is a useful tool for tracing an application's logic flow, printing data to the console, and debugging web and node applications. I, like the majority of developers, cannot survive without it.
However, Console.log should not be used in production since you do not want your app to display payload or errors there. If you frequently neglect to delete or comment out console messages in your code, add the following code to your root file to hide console.log messages in production.
if(process.env.NODE_ENV !=="development") console.log=()=>{};
We are assigning a useless empty arrow function to the console.log method, it will never be invoked. Reusing built-in JavaScript methods, often known as monkey patching, is frowned upon by the JavaScript community, but it also obscures our mistakes. Using the console.info() or console.error() methods, you can highlight critical developer mistakes in live code.
3. Currying event handlers
In JavaScript, currying is the process through which a function that accepts few arguments yields a function that only accepts one argument. When managing events in React, currying is highly effective; it keeps the code clean, understandable, and minimises inline event handling logic.
Take a look at the functional component:
function NewsPosts() {
const [posts, setPosts] = React.useState([]);
const [post, setPost] = React.useState(null);
const handlePost = (post) => {setPost(post)};
return (
<div>
<h3>Latest Post</h3>
<ul>
{posts.length > 0 &&
posts.map((post) => (
<li key={post.id} onClick={() => handlePost(post)}>
{post.body}
</li>
))}
</ul>
</div>
);
}
The component takes an array of posts, checks if elements are present in the array,renders them and uses a callback function to handle a click event on individual post item.
We can rewrite the function logic using currying as follows:
function NewsPosts() {
const [posts, setPosts] = React.useState([]);
const [post, setPost] = React.useState(null);
const handlePost = (post) => {
return (e) => {
e.preventDefault();
setPost(post);
};
};
return (
<div>
<h3>Latest Post</h3>
<ul>
{posts.length > 0 &&
posts.map((post) => (
<li key={post.id} onClick={handlePost(post)}>
{post.body}
</li>
))}
</ul>
</div>
);
}
The function handlePost is called directly during rendering but it is returned as a curry then invoked when a click event is fired. Don’t you think its a cleaner way of writing code?
4. Global This
With the advent of server side rendering utilising node.js, it is now important to determine if the programme is executing in a client-side or server-side context. By doing so, the application-crashing Node.js methods and window (browser) methods won't be mixed together.
Global this is a feature added to ES2019 to help identify the environment in which an application is running in order to prevent application failure.
To execute specific statements while determining whether you are executing in the browser or node environment;
if(globalThis.window)
console.log(`Running in the browser`)
else
console.log(`Running in node env`)
5. Don’t be eval
Eval is a built-in JavaScript method that allows you to evaluate and run JavaScript syntax that has been wrapped in a string.
Douglas Crockford claims in his book JavaScript: The Good Parts that the security problem with eval is that code contained inside a string can be exploited in cross-site attacks, with the result that "eval is evil"; for example,
eval("alert('You have been hacked'))
However, in React, eval can be used to securely set the state of several form input values with only one function. Given that React uses a virtual DOM to update the actual DOM, there are no security concerns to worry about.
Consider the following React component;
function MyForm() {
const [firstName, setFirstName] = React.useState("");
const [lastName, setLastName] = React.useState("");
const [age, setAge] = React.useState("");
const [gender, setGender] = React.useState("");
const [location, setLocation] = React.useState("");
const handleSubmit = (e) => {
e.preventDefault();
//send payload to server
};
return (
<form onSubmit={handleSubmit} style={{
display: "flex",
flexDirection: "column",
gap: 10,
maxWidth: 500,
}}>
<div>
<label htmlFor="FirstName">First Name</label>
<input
type="text"
name="FirstName"
id="FirstName"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
</div>
<div>
<label htmlFor="LastName">Last Name</label>
<input
type="text"
name="LastName"
id="LastName"
value={lastName}
onChange={(e) => setLastName(e.target.value)}
/>
</div>
<div>
<label htmlFor="Age">Age</label>
<input
type="text"
name="Age"
id="Age"
value={age}
onChange={(e) => setAge(e.target.value)}
/>
</div>
<div>
<label htmlFor="Male">
{" "}
<input
type="radio"
name="Gender"
id="Male"
value="Male"
onChange={handleChange}
/>
</label>
<label htmlFor="Female">
{" "}
<input
type="radio"
name="Gender"
id="Female"
value="Female"
onChange={handleChange}
/>
</label>
</div>
<div>
<label htmlFor="Location">Location</label>
<input
type="text"
name="Location"
id="Location"
value={location}
onChange={(e) => setLocation(e.target.value)}
/>
</div>
<button type="submit">Submit</button>
</form>
);
}
This is a straightforward form element that gathers user biodata, sets it to the appropriate state using the onChange event handler function, and dynamically binds values from state variables to the HTML inputs.
The drawback with inline onchange even is that it doesn't offer a mechanism to evaluate data or make the user interface interactive when the user triggers blur or focus events. So many onchange inlin event handlers setting state directly is overwhelming. We need a single source of truth to handle our onchange events.
In order to correct this, we employ the eval method, a single onchange event handler, the HTML input attribute name, which we use to dynamically setState using the eval method, and ultimately input values.
name
, id
and data-*
attribute are all valid HTML input attributes, however I personally favour name
attribute.
NB: The name of the HTML attribute property that will be utilised should resemble the name of the setState function that is set as the state variable.
const [lastName,setLastName]=React.useState(“”)
<input
type="text"
name="LastName" // this one should match LastName in setLastName
id="LastName"
value={lastName}
onChange={(e) => setLastName(e.target.value)}
/>
Updated function should now look like this:
function MyForm() {
const [firstName, setFirstName] = React.useState("");
const [lastName, setLastName] = React.useState("");
const [age, setAge] = React.useState("");
const [gender, setGender] = React.useState("");
const [location, setLocation] = React.useState("");
/**this function extracts the name attribute from target as well as
* its value then dynamically uses eval to set state of respective state variable */
const handleChange = (e) => {
// grab the value
const value = e.target.value;
// grab name attribute of element under change
const nameAttribute = e.target.name;
// concatenate set + name atrribute, i.e setAge, setLocation
// then evaluate the function using eval method
const setState = eval("set" + nameAttribute);
// get element by attribute select
const element = document.querySelector(`input[name="${nameAttribute}"]`);
// validate locatiom
if (nameAttribute === "Location") {
if (e.target.value.trim().length > 0) setState(value);
// give user feedback
element?.classList.remove("red-border");
} else {
// show some error
element?.classList.add("red-border");
}
// validate gender
if (e.target.type === "radio") {
// do necessary valdiation
}
};
const handleSubmit = (e) => {
e.preventDefault();
//send payload to server
};
return (
<form onSubmit={handleSubmit} style={{
display: "flex",
flexDirection: "column",
gap: 10,
maxWidth: 500,
}} >
<div>
<label htmlFor="FirstName">First Name</label>
<input
type="text"
name="FirstName"
id="FirstName"
value={firstName}
onChange={handleChange}
/>
</div>
<div>
<label htmlFor="LastName">Last Name</label>
<input
type="text"
name="LastName"
id="LastName"
value={lastName}
onChange={handleChange}
/>
</div>
<div>
<label htmlFor="Age">Age</label>
<input
type="text"
name="Age"
id="Age"
value={age}
onChange={handleChange}
/>
</div>
<p>Gender</p>
<div style={{ display: "flex", gap: 10 }}>
<label htmlFor="Male">
{" "}
<input
type="radio"
name="Gender"
id="Male"
value="Male"
onChange={handleChange}
/>Male
</label>
<label htmlFor="Female">
{" "}
<input
type="radio"
name="Gender"
id="Female"
value="Female"
onChange={handleChange}
/>Female
</label>
</div>
<div>
<label htmlFor="Location">Location</label>
<input
type="text"
name="Location"
id="Location"
value={location}
onChange={handleChange}
/>
</div>
<button type="submit"style={{ width: "100%", background: "skyblue" , padding: 0.5,
borderRadius: 5}} >Submit</button>
</form>
);
}
You'll now see that there is now a single handleChange method that manages all form inputs. This function takes the name attribute from the target property of event object e.target.name
, evaluates it to a setState function, and then captures the value e.target.value
of the element under change. Every input element can be validated adding blur events then using eval method inside blur event handlers. See how the eval approach simplifies the task at hand?
6. Is it mounted?
One perplexing aspect of the React useEffect hook is that it occasionally executes even if the component is not mounted at the moment. Performance problems may result from this if a component fetches data from a REST API and renders it even though the user is not currently browsing that part.
React use Effect hook executes once right after the initial render, while keeping an eye out for modifications to the dependency array, and while unmounting (clean up).To fix that, we declare a variable inside useEffect that checks if component is currently mounted.
const fetchData=()=>{
// get some data from the server
}
React.useEffect(()=>{
let mounted=true;
if(!mounted) return; // if mounted is false, return from the hook since it is not mounted
// if its mounted perform your side effects
fetchData()
return()=>{
mounted=false;}
},[]) // you can add your dependencies to the array
Top comments (0)