With the useState() hook we create a state variable (message) to store the current value of the input field. We also create another state variable (updated) that will be updated with the input field value when the button is clicked.
We set an onChange event handler on the input field to make this handler get called whenever the input value changes. In the handler, we use the event.target property to access the object representing the input element. The value property of this object contains the input value, so we pass it to setMessage() to update message, and this reflects on the page.
After setting up the controlled input, we can now use message outside the handleChange handler to access the current value of the input field.
So in the onClick event handler we set on the button, we use setUpdated(message) to update the updated variable with the current input field value.
Get value of uncontrolled input on button click
To get the value of an uncontrolled input on button click in React:
Create a ref for the input field
Set an onClick event handler on the button.
Use the ref object to access the current input value in the event handler.
While the data in a controlled input is handled by React state, the data in an uncontrolled input is handled by the DOM itself. This is why the input in the example above doesn’t have a value prop or onChange event handler set. Instead, we access the input field value with a React ref. The DOM updates this value when the text in the input is changed.
We create a ref object with the useRef() hook and set it to the ref prop of the input. Doing this sets the current property of the ref object to the DOM object that represents the input element.
useRef() returns a mutable ref object that does not change value when a component is updated. Also, modifying the value of this object’s current property does not cause a re-render. This is in contrast to the setState update function returned from useState().
Although the React documentation recommends using controlled components, uncontrolled components offer some advantages. You might prefer them if the form is very simple and doesn’t need instant validation, and values only need to be accessed when the form is submitted.
To link a local image in React, import the image at the top of the file and assign it to the src prop of an img element.
For example:
App.js
// 👇 import image from file
import myImage from './my-image.jpg';
export default function App() {
return (
<div>
{/* 👇 show image */}
<img src={myImage} alt="Trees" height="200" />
<br />
<span
style={{
color: 'green',
fontSize: '1.2em',
fontWeight: 'bold',
}}
>
Trees
</span>
</div>
);
}
This approach works when using a Webpack-based tool like Create React App.
Note that the image file must be within the project directory to be imported successfully. An error will occur if the file is outside the project directory.
Link image in React with require() function
Alternatively, we can use the require() function to link an image in React.
The following code example will produce precisely the same result on the page as the first example.
The advantage require() has here is that it doesn’t need to be at the top of the page. We can simply assign the result of require() to the src prop without having to store it in a variable.
Link image in public folder
Another way to link an image in React is to place it in the public folder and reference it with its relative path.
For example, if we placed the my-image.png file in the public folder, we’ll be able to display it in the page like this:
Using the public folder is advantageous when we have many images that we want to display dynamically.
In the following examples, we dynamically display 100 images placed in a grid subfolder under public, and named with a certain pattern (image-1.jpg, image-2.jpg, …, image-100.png) in a grid.
We used inline styles to make the text bold. The style attribute of a React element accepts a JavaScript object with camelCased properties instead of a CSS kebab-cased string. So, fontWeight sets the font-weight CSS property.
If we don’t need to control the boldness with a condition, then we can just wrap the text with a b element.
We use a state variable named bold to store the current checked state of the checkbox and to determine whether the relevant text should be bold or not.
We attach an event listener to the onChange event, so it is called when the checkbox is checked or unchecked. In this listener, we use the setBold function to update the value of bold and change the boldness of the text.
Bold text with custom component
If we frequently need make text bold, we can abstract the logic into a reusable custom component.
App.js
function BoldText({ children }) {
return (
<span style={{ fontWeight: 'bold' }}>{children}</span>
);
}
export default function App() {
return (
<div>
Coding <BoldText>Beauty</BoldText>
</div>
);
}
This code will produce the same result on the web page.
Whatever text is place within the <BoldText> and </BoldText> tags will have a bold font.
Conditionally bold text with custom component
To make text bold conditionally with a custom component, we can create a boolean bold property that will determine whether the child text of the component should be bold or not.
Using the ternary operator, we set the className property to the bold class if the bold variable is true. Otherwise, we set className to an empty string ('').
Tip: Instead of the ternary operator, you can use the clsx utility from NPM to more easily construct class names from a set of conditions in React.
We use the useState() to create a state variable in the component. This hook returns an array of two variables, generally called state and setState. The state variable (visible) holds the current visibility state, and the setState function (setVisible) updates it.
const [visible, setVisible] = useState(true);
We set an event handler to the onClick event of the button, so when the button is clicked, the handler function will be called.
<button onClick={removeElement}>Remove</button>
In the handler function, we use the setState function for the visibility state to update the state.
Instead of passing the negated value directly, we pass a callback function to setState that returns the negated value. This ensures that we always get the most recent state value.
Tip
React batches state changes for performance reasons, so the state may not be updated immediately after setState is called, in the order we might expect. This is why we always pass a function to setState when the new state is computed from the data of the previous state.
Remove element from list onclick
To remove an element from a list onclick:
Attach an event handler to the onClick event of every element in the array representing the list.
In the event handler for a particular element, call the filter() method on the array, specifying a condition that is true for every element in the array apart from the one to be removed.
Use setState to update the state array with the result returned from filter().
With the map() method, we render a button for each element in the array. For each button, we attach an event handler that will call the removeElement() method, passing as an argument the index of the element that the button represents.
removeElement() removes an element by returning a condition from the filter() callback that is true only for elements in the array that don’t have the index passed to removeIndex(). Doing this excludes the element with that index from the array, so when the array state is updated, the button representing that element is no longer rendered.
Trying to remove the element from the array by modifying it using a function like splice() will not work:
const removeElement = (index) => {
// ⚠️ Mutating the array like this will not update the view
fruits.splice(index, 1);
};
State is meant to be immutable in React, so we can’t update the array by mutating it. It has to be replaced with a new array returned from filter() for the view to update.
Remove object element from list onclick
We can also use this approach to remove an element represented by an object from a list onclick.
Instead of filtering by index, this time we filter by the id property to remove an item from the array and remove the element from the list in the DOM.
In this article, we’ll look at different ways to easily call an async function inside the React useEffect() hook, along with pitfalls to avoid when working with async/await.
Call async Functions With then/catch in useEffect()
async functions perform an asynchronous operation in JavaScript. To wait for the Promise the async function returns to be settled (fulfilled or rejected) in the React useEffect() hook, we could use its then() and catch() methods:
In the following example, we call the fetchBooks() async method to fetch and display stored books in a sample reading app:
async/await Problem: async Callbacks Can’t Be Passed to useEffect()
Perhaps you would prefer to use the async/await syntax in place of then/catch. You might try doing this by making the callback passed to useEffect()async.
This isn’t a good idea though, and if you’re using a linter it will inform you of this right away.
// ❌ Your linter: don't do this!
useEffect(async () => {
try {
const books = await fetchBooks();
setBooks(books);
} catch {
console.log('Error occured when fetching books');
}
}, []);
Your linter complains because the first argument of useEffect() is supposed to be a function that either returns nothing or returns a function to clean up side effects. But async functions always return a Promise (implicitly or explicitly), and Promise objects can’t be called as functions. This could cause real issues in your React app, such as memory leaks.
In this example, because the callback function is async, it doesn’t actually return the defined clean-up function, but rather a Promise object that is resolved with the clean-up function. Hence, this clean-up function is never called, and the observer is never unsubscribed from the observable, resulting in a memory leak.
So how can we fix this? How can we use the await operator with an async function in the useEffect() hook?
async/await Solution 1: Call async Function in IIFE
As the name suggests, an IIFE is a function that runs as soon as it is defined. They are used to avoid polluting the global namespace and in scenarios where trying an await call could cause problems in the scope containing the IIFE (e.g., in the useEffect() hook, or in the top-level scope for pre-ES13 JavaScript).
async/await Solution 2: Call async Function in Named Function
Alternatively, you can await the async function inside a named function:
useEffect(() => {
// Named function "getBooks"
async function getBooks() {
try {
const books = await fetchBooks();
setBooks(books);
} catch (err) {
console.log('Error occured when fetching books');
}
}
// Call named function
getBooks();
}, []);
Remember the example using the observable pattern? Here’s how we can use a named async function to prevent the memory leak that occurred:
// ✅ Callback is not async
useEffect(() => {
const observer = () => {
// do stuff
};
// Named function "fetchDataAndSubscribe"
async function fetchDataAndSubscribe() {
await fetchData();
observable.subscribe(observer);
}
fetchDataAndSubscribe();
// ✅ No memory leak
return () => {
observable.unsubscribe(observer);
};
}, []);
async/await Solution 3: Create Custom Hook
We can also create a custom hook that behaves similarly to useEffect() and can accept an async callback without causing any issues.
In this article, we’ll look at different ways to call an async function in the useEffect() hook, along with pitfalls to avoid when working with async/await.
Calling async Functions With then/catch in useEffect()
async functions perform an asynchronous operation in JavaScript. To wait for the Promise the async function returns to be settled (fulfilled or rejected) in the React useEffect() hook, we could use its then() and catch() methods:
In the following example, we call the fetchBooks() async method to fetch and display stored books in a sample reading app:
async/await Problem: async Callbacks Can’t Be Passed to useEffect()
Perhaps you would prefer to use the async/await syntax in place of then/catch. You might try doing this by making the callback passed to useEffect()async.
This isn’t a good idea though, and if you’re using a linter it will inform you of this right away.
// ❌ Your linter: don't do this!
useEffect(async () => {
try {
const books = await fetchBooks();
setBooks(books);
} catch {
console.log('Error occured when fetching books');
}
}, []);
Your linter complains because the first argument of useEffect() is supposed to be a function that either returns nothing or returns a function to clean up side effects. But async functions always return a Promise (implicitly or explicitly), and Promise objects can’t be called as functions. This could cause real issues in your React app, such as memory leaks.
In this example, because the callback function is async, it doesn’t actually return the defined clean-up function, but rather a Promise object that is resolved with the clean-up function. Hence, this clean-up function is never called, and the observer never unsubscribed from the observable, resulting in a memory leak.
So how can we fix this? How can we use the await operator with an async function in the useEffect() hook?
async/await Solution 1: Call async Function in IIFE
As the name suggests, an IIFE is a function that runs as soon as it is defined. They are used to avoid polluting the global namespace and in scenarios where trying an await call could cause problems in the scope containing the IIFE (e.g., in the useEffect() hook).
async/await Solution 2: Call async Function in Named Function
Alternatively, you can await the async function inside a named function:
useEffect(() => {
// Named function "getBooks"
async function getBooks() {
try {
const books = await fetchBooks();
setBooks(books);
} catch (err) {
console.log('Error occured when fetching books');
}
}
// Call named function
getBooks();
}, []);
Remember the example using the observable pattern? Here’s how we can use a named async function to prevent the memory leak that occurred:
// ✅ Callback is not async
useEffect(() => {
const observer = () => {
// do stuff
};
// Named function "fetchDataAndSubscribe"
async function fetchDataAndSubscribe() {
await fetchData();
observable.subscribe(observer);
}
fetchDataAndSubscribe();
// ✅ No memory leak
return () => {
observable.unsubscribe(observer);
};
}, []);
async/await Solution 3: Create Custom Hook
We can also create a custom hook that behaves similarly to useEffect() and can accept an async callback without causing any issues.
In this article, we’re going to learn how to easily remove an item from a state array in React.
The Array filter() Method
To remove an item from a state array in React, call the filter() method on the array, specifying a test that every item in the array apart from the one to be removed will pass, then update the state with the result of filter() with setState.
We remove the fruit object with the id2 by returning a condition from the filter() callback that is true only for the items in the array that don’t have an id of 2. Doing this excludes the target item from the array returned from filter().
Since App here is a functional component, we use the useState() React hook to create the initial state array. The first value useState() returns lets us access the state data. The second value is a function used to update the state (generically called setState). We pass a function to setState (named setFruits here) to ensure that we get the current/latest state.
Tip: Always pass a function to setState when the new state is computed from the current state data.
Don’t Modify State Directly in React
Note that trying to remove the item from the array by modifying it directly using a function like splice() will not work:
const removeSecond = () => {
// Find the index of the object to be removed
const secondIndex = fruits.findIndex((fruit) => fruit.id === 2);
// Mutating the array like this will not update the view
fruits.splice(secondIndex, 1);
};
State is meant to be immutable in React, so we can’t update the array by mutating it. It has to be replaced with a new array returned from filter() for the view to update.
Remove Items from a State Array Based on Multiple Conditions
If you need to remove an item from the state array based on multiple conditions, you can use the logical AND (&&) or logical OR (&&) operator.
Using the Logical OR (||) Operator
Here is an example of using the logical OR (||) operator to remove an item from a state array.
Combining a set of operands with the || operator will result in trueif at least one of the operands evaluates to true. By using this operator with the filter() method, we return a new array containing only the fruit objects with a name equal to 'Orange' or 'Apple'.
Using the Logical AND (&&) Operator
Here is an example of using the logical AND (&&) operator to remove an item from a state array:
Combining operands with the && operator will result in trueonly if all the operands are true.
By combining the filter() method with the && operator, we are able to specify a compound boolean expression that removes the fruit objects with ids of 2 and 4.
Simplifying Compound Boolean Expressions with De Morgan’s Laws
We can use one of De Morgan’s laws to convert the AND condition from our previous example to an OR condition and reduce the number of negations.
To use a button as a link in React, wrap the button in an anchor (<a>) element. Clicking a link button will make the browser navigate to the specified URL.
If you’re using React Router, then wrap the button in the Link component instead, to make the browser navigate to the specified route without refreshing the page when the button is clicked.
JavaScriptCopied!
import { Link } from 'react-router-dom';
export default function MyComponent() {
return (
<div>
<Link to="/posts">
<button>Posts</button>
</Link>
</div>
);
}
The react-router-domLink component renders an anchor element, so it works similarly to the first example.
We can also use custom button components as links by wrapping them with an anchor element or Link component. For example:
JavaScriptCopied!
import { Link } from 'react-router-dom';
function MyCustomButton({ children }) {
return <button>{children}</button>;
}
export default function MyComponent() {
return (
<div>
<Link to="/posts">
<MyCustomButton>Posts</MyCustomButton>
</Link>
</div>
);
}
Use Material UI button as link
When using Material UI, we can specify a link for the Button component using the href prop.
JavaScriptCopied!
import { Button } from '@mui/material';
export default function MyComponent() {
return (
<div>
<Button href="/posts">Posts</Button>
</div>
);
}
Use Material UI button as React Router link
To use as a React Router Link, we can use the component prop of the Button.
JavaScriptCopied!
import { Button } from '@mui/material';
import { Link } from 'react-router-dom';
export default function MyComponent() {
return (
<div>
<Button component={Link} to="/posts">
Posts
</Button>
</div>
);
}
Other Material UI components like IconButton also have a component prop. Setting this prop is useful when we want the button component to inherit its color from its parent.
In this scenario, if we wrap the component with a Link, it will inherit its color from the Link instead of the intended parent. For example:
JavaScriptCopied!
import { IconButton, Box, Typography } from '@mui/material';
import { Link } from 'react-router-dom';
import { Photo } from '@mui/icons-material';
export default function MyComponent() {
return (
// We want the IconButton to inherit its parent color (white)
<Box sx={{ backgroundColor: 'black', color: 'white', padding: 2 }}>
<Typography>Lorem Ipsum</Typography>
{/* But this wrapping makes it inherit from this Link */}
<Link to="/photos">
<IconButton color="inherit">
<Photo />
</IconButton>
</Link>
</Box>
);
}
We can fix this issue by setting the component prop to a Link instead of wrapping:
JavaScriptCopied!
import { IconButton, Box, Typography } from '@mui/material';
import { Link } from 'react-router-dom';
import { Photo } from '@mui/icons-material';
export default function MyComponent() {
return (
<Box sx={{ backgroundColor: 'black', color: 'white', padding: 2 }}>
<Typography>Lorem Ipsum</Typography>
{/* Setting the "component" prop to a "Link" component */}
<IconButton component={Link} to="/photos" color="inherit">
<Photo />
</IconButton>
</Box>
);
}
In this article, we’re going to learn how to build a web app that will let us easily remove leading and trailing spaces from any text, with the ability to optionally preserve the indentation of the text. We’ll be using the React.js library to build this tool, let’s get started.
Let’s begin by creating a new React app using Create React App. We’ll be using Yarn.
yarn create-react-app remove-spaces
We’ll also be using a bit of TypeScript, you can set it up using the instructions here.
Writing the removeSpaces() Function
The core part of the app will be a removeSpaces() function that takes a string as input and returns a new string with the spaces removed. Let’s write this function in a new remove-spaces.ts file.
Apart from the input string, the function accepts options that will allow the user to customize how the spaces are removed.
When leading is true and preserveIndent is false, the leading spaces are removed from the text, apart from the spaces that add indentation.
When leading is true and preserveIndent is false, all the leading spaces are removed from the text.
When trailing is true, all the trailing spaces are removed from the text.
The function creates a regular expression from the combination of these options. It uses the String replace() method to replace each line of the text with captured groups from the regex.
Testing the removeSpaces() function
We can test this function to be sure it works as intended. Let’s install the Jest testing framework to do this.
yarn add --dev jest ts-jest @types/jest
Initialize ts-jest with the following command:
yarn ts-jest config:init
Let’s write some tests for the function in a new remove-spaces.test.ts file:
The function should pass all these tests if it was written correctly.
Creating the Text Inputs
It’s time for us to start creating the user interface with React. We’ll begin with the text inputs. We’ll create two – one will take will user input, and the other will be readonly and display the output.
We’ll be using the Material UI framework to make the app look great, you can set it up using the instructions here.
Let’s create the options that will let the user decide how the spaces will be removed from the text. There will be three boolean options, each represented with a checkbox:
Remove leading spaces
Remove trailing spaces
Preserve indent
We’ll pass the options directly to the removeSpaces() function when the user decides to remove the spaces.
Our space remover app is complete! We’ve been able to build a handy utility for removing leading and trailing spaces from any text and preserving indentation if necessary.
What Can This Tool Be Used for?
At Coding Beauty, we found this tool useful when creating code snippets displaying a portion of code from an HTML or JSX markup that was indented by some amount. For example, in our Material UI button tutorial, there were times when the file for an example contained markup like this:
But we would only want to show the section of the file relevant to the example:
This tool helped format the relevant section properly by removing the spaces.
What about String trim()?
We couldn’t use the trim() or trimStart() string methods because then it wouldn’t be possible to preserve the indent of the entire text. These methods can only remove all the leading spaces in a given string.
A button is a commonly used component that adds interactivity to a UI. In this article, we’re going to learn how to easily create and customize buttons in Material UI.
The Material UI Button Component
We can use the Button component from Material UI to create buttons. It has a variant prop used to display a text, contained, or outlined button.
Text buttons are suitable for actions of low significance in an app, like the closing of a dialog. Setting the variant prop to text displays a text button.
Outlined buttons indicate actions of mid-level significance. They are a lower emphasis alternative to contained buttons and a higher emphasis alternative to text buttons. Setting the variant prop to outlined displays and outlined button.
The size prop of the Button component allows us to create buttons of different sizes.
JavaScriptCopied!
import { Box, Button } from '@mui/material';
export default function App() {
return (
<Box>
<Box sx={{ '& button': { m: 1 } }}>
<div>
<Button size="small">Small</Button>
<Button size="medium">Medium</Button>
<Button size="large">Large</Button>
</div>
<div>
<Button
variant="outlined"
size="small"
>
Small
</Button>
<Button
variant="outlined"
size="medium"
>
Medium
</Button>
<Button
variant="outlined"
size="large"
>
Large
</Button>
</div>
<div>
<Button
variant="contained"
size="small"
>
Small
</Button>
<Button
variant="contained"
size="medium"
>
Medium
</Button>
<Button
variant="contained"
size="large"
>
Large
</Button>
</div>
</Box>
</Box>
);
}
Icon and Label Buttons
Including an icon in a button can make clearer to the user the action the button performs. Assigning the icon component to the startIcon or endIcon prop aligns the icon to the left or right of the label respectively.
JavaScriptCopied!
import { Button, Stack } from '@mui/material';
import {
Settings as SettingsIcon,
PlayArrow as PlayArrowIcon,
} from '@mui/icons-material';
export default function App() {
return (
<Stack
spacing={2}
direction="row"
>
<Button
variant="contained"
startIcon={<PlayArrowIcon />}
>
Play
</Button>
<Button
variant="outlined"
endIcon={<SettingsIcon />}
>
Settings
</Button>
</Stack>
);
}
Icon Buttons in Material UI
Icon buttons can help save screen space and ease user recognition. We can use the IconButton component from Material UI to create them.