React Tips — Query Strings, Wrappers, and Clicks Outside

John Au-Yeung - Oct 19 '20 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

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>
)

Enter fullscreen mode Exit fullscreen mode

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 />
  </>
)

Enter fullscreen mode Exit fullscreen mode

or:

return (
  <React.Fragment>
    <Child1 />
    <Child2 />
  </React.Fragment>
)

Enter fullscreen mode Exit fullscreen mode

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]
}))

Enter fullscreen mode Exit fullscreen mode

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]);

Enter fullscreen mode Exit fullscreen mode

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>;
  }
}

Enter fullscreen mode Exit fullscreen mode

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>;
}`

Enter fullscreen mode Exit fullscreen mode

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")

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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>;
}

Enter fullscreen mode Exit fullscreen mode

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>;
}

Enter fullscreen mode Exit fullscreen mode

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.

The post React Tips — Query Strings, Wrappers, and Clicks Outside appeared first on The Web Dev.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .