React is a popular library for creating web apps and mobile apps.
In this article, we’ll look at some tips for writing better React apps.
Fix ‘Adjacent JSX elements must be wrapped in an enclosing tag’ Error
All components must have an outer element surrounding them.
For instance, we can write:
return (
<div>
<Child1 />
<Child2 />
</div>
)
We have a div surrounding all the child elements.
Also, we can use a fragment to surround our components if we don’t want to render a wrapper element.
For instance, we can write:
return (
<>
<Child1 />
<Child2 />
</>
)
or:
return (
<React.Fragment>
<Child1 />
<Child2 />
</React.Fragment>
)
Correct Way to Modify State Arrays in React
To modify a state array correctly in React, we should call setState
‘s state change function with a callback that returns the new array.
This way, we know the new value is derived from the most current value.
For instance, we can write:
this.setState(prevState => ({
array: [...prevState.array, newThing]
}))
We add newThing
to the end of the array.
If we use a function component, we can write:
`const [arr, setArr] = useState([]);
`//...
setArr(prevArr => [...prevArr, newThing]);
Detect Click Outside React Component
We can detect clicks outside a React component by listening to the documen
‘s click event.
This way, we can handle clicks of any element.
For instance, we can write:
import React, { Component } from 'react';
export default class App extends Component {
constructor(props) {
super(props);
this.setWrapperRef = this.setWrapperRef.bind(this);
this.handleClickOutside = this.handleClickOutside.bind(this);
}
componentDidMount() {
document.addEventListener('mousedown', this.handleClickOutside);
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleClickOutside);
}
setWrapperRef(node) {
this.wrapperRef = node;
}
handleClickOutside(event) {
if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
alert('clicked outside');
}
}
render() {
return <div ref={this.setWrapperRef}>hello</div>;
}
}
We call the docuyment.addEventListener
method to listen to the click event in the componentDidMount
hook.
And we remove the listener with the component unmounts with removeListener
in the componentWillUnmount
hook.
Then we set the ref of the div so that we can check which element is clicked handleclickOutside
and if it’s inside the component with contains
.
Likewise, we can do the same with function components with hooks.
For instance, we can write:
import React, { useRef, useEffect } from "react";
function useClickOutside(ref) {
useEffect(() => {
function handleClickOutside(event) {
if (ref.current && !ref.current.contains(event.target)) {
console.log("clicked outside");
}
}
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref]);
}
`export default function App() {
const wrapperRef = useRef(null);` useClickOutside`(wrapperRef);
return <div ref={wrapperRef}>hello</div>;
}`
We created the useClickOutside
hook to add the event listener when the hooked loads.
Then in the function, we return in the useEffect
callback, we remove the click listener.
We watch the ref
for changes, so we have [ref]
as the 2nd argument of useEffect
.
Then we call useRef
to create the ref, assign it to the div, and call useClickOutside
with it.
How to Get Parameter Value from a Query String
If we’re using React Router, we can get the parameter value from the query string with the URLSearchParams
constructor and the location.search
prop.
For instance, we can write:
new URLSearchParams(this.props.location.search).get("foo")
this.prop.location.search
has the query string.
Then we parse it into an object with URLSearchParams
constructor.
And we call get
with the key of the query parameter we want to get.
Also, we can use:
this.props.match.params.foo
to get the query parameter with key foo
.
With the hooks version of the React Router, we can write:
import { useLocation } from 'react-router';
import queryString from 'query-string';
const App = React.memo((props) => {
const location = useLocation();
console.log(queryString.parse(location.search));
return <p>search</p>;
}
We use the useLocation
hook from React Router to get the location
object from the hook.
Then we can use the queryString
package to parse the query string.
We can also replace the query-string package with the URLSearchParams
constructor:
import { useLocation } from 'react-router';
const App = React.memo((props) => {
const location = useLocation();
console.log(new URLSearchParams(location.search));
return <p>search</p>;
}
Conclusion
We should wrap our components with a root element or fragment.
The right way to modify arrays is to pass in a function to setState
or state change function.
We can watch for clicks outside a component by adding event listeners.
Also, we can get the query string from the component with React Router.