Categories
React Tips

React Tips — Setting State and Internationalization

React is the most used front end library for building modern, interactive front end web apps. It can also be used to build mobile apps.

In this article, we’ll look at how to set multiple states sequentially and the internationalization of React apps.

setState Updater Function

In React class-based components, the setState method either takes an object with the state to update or a function.

setState also takes a function, which preserves the order of how the state should be applied as well as making sure that all previous states are flushed through.

For instance, we can call setState with a callback function instead of an object as follows:

import React, { Suspense } from "react";

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  increment() {
    this.setState((state, props) => {
      return {
        count: state.count + 1
      };
    });

    this.setState((state, props) => {
      return {
        count: state.count + 2
      };
    });
  }

  render() {
    return (
      <>
        <button onClick={this.increment.bind(this)}>Increment</button>
        <p>{this.state.count}</p>
      </>
    );
  }
}

In the code above, we have the increment method, which first increases the count by 1, then it increases the count again by 2.

Since we passed in a callback function to setState , count should increase by 3 every time that we click the Increment as the state changes are applied sequentially.

Use Prop Types to Check to Validate Prop Data

By default, React lets us pass anything from parent components to child components via props. This isn’t ideal because it’s very easy to make a mistake that may cause runtime errors in production.

Therefore, we should use React’s built-in prop-type validation feature to check the data type of props. We can also use it to check if the prop value has the format that we want them to be in.

There’s built-in prop type for common JavaScript data types. In addition, we can check for a combination of one or more types and we can also pass in a custom validation to check for the prop data.

For instance, we can use it as follows:

import React from "react";
import PropTypes from "prop-types";

const Foo = ({ data }) => {
  return <p>{data}</p>;
};

Foo.propTypes = {
  data: PropTypes.string
};

export default function App() {
  return <Foo data="bar" />;
}

In the code above, we have:

Foo.PropTypes = {
  data: PropTypes.string
};

to check that the data prop is indeed a string. In the code above, we passed in a string as the value of the data prop. Therefore, we should see the p element displayed with the text ‘bar’ inside.

Otherwise, we would get an error.

We can add our own prop data validation as follows:

import React from "react";

const Foo = ({ data }) => {
  return <p>{data}</p>;
};

Foo.propTypes = {
  data(props, propName, componentName) {
    if (!/bar/.test(props[propName])) {
      return new Error("I want bar");
    }
  }
};

export default function App() {
  return <Foo data="baz" />;
}

In the code above, we have:

Foo.propTypes = {
  data(props, propName, componentName) {
    if (!/bar/.test(props[propName])) {
      return new Error("I want bar");
    }
  }
};

Therefore, if we didn’t pass in 'bar' as the value of the data prop into Foo , we’ll get the error ‘I want bar’ logged in the console. We pass in 'baz' , so we’ll get the error.

Internationalization

The react-intl library is great for internationalization of React apps. It’s made by Yahoo. It has lots of components for doing various things like formatting dates for a specific locale, pluralization and more.

We can install it by running:

npm i react-intl

For instance, we can use it as follows:

import React from "react";
import { IntlProvider, FormattedDate } from "react-intl";

export default function App() {
  return (
    <IntlProvider locale="fr">
      <FormattedDate value={new Date(2019, 0, 1)} weekday="long" />
    </IntlProvider>
  );
}

In the code above, we referenced the IntlProvider component from react-intl , and inside it, we have the FormattedDate component to format the date that’s passed into the value prop.

Then we should see ‘ mardi’ on the screen because we specified that the locale is 'fr' , which is French.

react-intl has many other components that we can use to make internalization easy, so we should use this instead of writing the code ourselves.

Conclusion

Setting state in a component is easier if we pass in a callback function instead of an object. This is because the setting of the states will be done sequentially instead of at an indeterminate time. This makes running setState multiple times easy if we need to set them sequentially.

To make passing props less error-prone, we should use prop-types to check for the correct prop type and format when props are being passed in. React will log errors to the console the type or format doesn’t match what we specified.

Finally, the internationalization of Reach apps is easy if we use the react-intl library. It has components for doing things like formatting dates and pluralization for different locales.

Categories
React Tips

React Tips — Render Props and Forward Refs

React is the most used front end library for building modern, interactive front end web apps. It can also be used to build mobile apps.

In this article, we’ll look at how to use render props to create a component that renders things flexibly and passing refs to a child with forwarding refs.

Render Props

Render prop is a pattern where we pass in the render function as a prop. To use the pattern, we create a component that calls the render function from props. Then from another component, we pass in the render prop with the function as the value to the component which calls render .

For instance, we can write the following code:

import React from "react";

const RenderComponent = ({ render }) => {
  const [foo] = React.useState("foo");
  const [bar] = React.useState("bar");

  return render({
    foo,
    bar
  });
};

export default function App() {
  return (
    <>
      <RenderComponent
        render={({ foo, bar }) => (
          <p>
            {foo} {bar}
          </p>
        )}
      />
      <RenderComponent
        render={({ foo, bar }) => (
          <p style={{ color: "green" }}>
            {foo} {bar}
          </p>
        )}
      />
    </>
  );
}

In the code above, we have the RenderComponent , which calls the render function passed in from props. It just calls the render function that’s passed in from props with the states inside RenderComponent .

Then in App , we referenced RenderComponent twice, with the render prop set the different functions for each.

Therefore, we should see ‘foo bar’ displayed twice, with the 2nd one being green.

This is useful for formatting data differently from the same state without repeating code.

Forward Refs

Forwarding refs means that we are getting the refs from a child component from a parent component.

For instance, if we want to get the ref of a button that resides in a custom button component, we can write the following code:

import React, { useEffect } from "react";

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref}>{props.children}</button>
));

export default function App() {
  const buttonRef = React.createRef();

  useEffect(() => {
    buttonRef.current.focus();
  }, []);

  return (
    <>
      <FancyButton ref={buttonRef}>Click me!</FancyButton>;
    </>
  );
}

In the code above, we have the FancyButton component, which has the button element, which we want to access. To let us access it from App or another component, we call React.forwardRef , which takes a callback with 2 parameters, props and ref .

The props have the props, and the ref is the ref that we can access from the outside. We set the ref prop to the ref parameter so to set the ref to the button.

Then in App , we create the buttonRef and pass it into ref . Then in the useEffect callback, we call buttonRef.current.focus(); to focus the button when App load since we have an empty array as the 2nd argument.

Forwarding refs are also used with 3rd party components. For instance, if we have to use the react-hook-form package and we’re using our own custom input control components, then we have to call forwardRef as follows:

import React from "react";
import { useForm } from "react-hook-form";

const Select = React.forwardRef(({ label }, ref) => (
  <>
    <label>{label}</label>
    <select name={label} ref={ref}>
      <option value="10">10</option>
      <option value="20">20</option>
    </select>
  </>
));

export default function App() {
  const { register, handleSubmit } = useForm();

  const onSubmit = () => {};

  return (
    <>
      <form onSubmit={handleSubmit(onSubmit)}>
        <Select label="Age" ref={register} />
        <input type="submit" />
      </form>
    </>
  );
}

In the code above, we created a custom select control called Select , which is created by calling forwardRef with a callback that takes the ref as the 2nd parameter, we set it as the value of the ref prop in the select element.

Then we can access the ref of select from App .

Conclusion

Render props is the pattern where we pass in the render function as a prop into a child component. The child component has the states that are rendered by the function we passed into the render prop.

Then we can reference that child component multiple times with different render functions.

Forwarding refs let us access the ref of an element from a child component from within the parent. This is useful for custom components that are used for customizing an existing HTML element.

Categories
React Tips

React Tips — Elements and Caching Values

React is the most used front end library for building modern, interactive front end web apps. It can also be used to build mobile apps.

In this article, we’ll look at various less common features that are helpful for developing React apps.

Create React Elements with Strings

We can reference React elements with strings instead of JSX. HTML elements can be written with strings instead of JSX.

For instance, we can write the following code:

import React from "react";

const Component = "div";

export default function App() {
  return <Component className="App">hello</Component>;
}

In the code above, we have Component set to 'div' , which means that Component is a div element. This is good because we can change the Component ‘s element tag dynamically without hassle.

For instance, we can make a toggle to switch between div and p as follows:

import React from "react";

export default function App() {
  const [Component, setComponent] = React.useState("div");
  return (
    <>
      <button
        onClick={() =>
          setComponent(Component => (Component === "div" ? "p" : "div"))
        }
      >
        Toggle Tag
      </button>
      <Component className="App">hello</Component>
    </>
  );
}

In the code above, we have a button to toggle the tag of Component between div and p.

Therefore, when we click the button, we’ll see that the tag of Component switches between div and p as we click the button.

Retain Previous Values

We can use the useRef hook to retain the previous value of a prop or state.

For instance, we can keep the old value and the new value of a state as follows:

import React from "react";

export default function App() {
  const [name, setName] = React.useState("bob");
  const prevNameRef = React.useRef("");

  React.useEffect(() => {
    prevNameRef.current = name;
  }, [name]);

  const prevName = prevNameRef.current;

  return (
    <div>
      <button
        onClick={() => setName(name => (name === "bob" ? "jane" : "bob"))}
      >
        Toggle Name
      </button>
      <p>Current name:</p>
      <p>{name}</p>
      <p>Previous name:</p>
      <p>{prevName}</p>
    </div>
  );
}

In the code above, we have the name state and the setName function to set the value of name .

Then in the button, we call the setName function when we click it. It toggles between 'bob' and 'jane' .

In the useEffect hook, we watch the value of name , which sets the prevNameRef.current to name to keep the original value. Then we set prevNameRef.current to prevName so to keep things short in the return statement.

In the end, we’ll see the old and new values display in the returned JSX.

Use React.useRef for Flexible Non-Stale Value Checks

One way to check if some data is loaded when the component loads are to use the useRef hook to keep track of whether the piece of data is loaded.

For instance, we can write the following code to do that:

import React from "react";

export default function App() {
  const [name, setName] = React.useState("");
  const loaded = React.useRef(false);

  React.useEffect(() => {
    if (!loaded.current) {
      setName("bob");
    }
    loaded.current = true;
    return () => (loaded.current = false);
  });

  return <div>{name}</div>;
}

In the code above, we check the useEffect callback that checks if loaded.current is true . If it’s not, then we call setName to set the name state’s value.

In the useEffect callback, we also have:

return () => (loaded.current = false);

to reset loaded.current to false when App unloads.

Therefore, we’ll see that the component loads with the name ‘bob’ displayed.

Memoize Values with the useMemo Hook

We can also use the useMemo hook to create a memoized values, which means that it’s cached as long as it or its dependencies don’t change.

useMemo runs during rendering. Therefore, we shouldn’t run anything that we wouldn’t do during rendering.

It’s used as a performance optimization, but it’s not a guarantee of the integrity of the value because it might change later.

For instance, we can use it as follows:

import React from "react";

export default function App() {
  const [firstName, setFirstName] = React.useState("");
  const [lastName, setLastName] = React.useState("");
  const name = React.useMemo(() => `${firstName} ${lastName}`, [
    firstName,
    lastName
  ]);

  return (
    <div>
      <input value={firstName} onChange={e => setFirstName(e.target.value)} />
      <input value={lastName} onChange={e => setLastName(e.target.value)} />
      <p>{name}</p>
    </div>
  );
}

In the code above, we used useMemo to watch firstName and lastName ‘s values and then derive a new value name from combining the 2.

Then when we enter text into the input, we’ll see that it updates the value of name . However, it’ll cache the existing value if firstName or lastName don’t change.

Conclusion

We can use the useRef and useMemo hooks to cache data. Also, we can create HTML elements with strings. This means that we can render HTML elements dynamically.

Categories
React Tips

React Tips — Component Organization

React is the most used front end library for building modern, interactive front end web apps. It can also be used to build mobile apps.

In this article, we’ll look at ways to organize our component structure to make maintenance easy.

Container and Presentational Components

We should separate our components for doing logic from the ones that are presenting the data. This keeps components small and easy to test. Testing presentational components is easy since all they do is get data and present them.

Container components don’t render anything presentational, so we only have to check the logic. Therefore, testing container components would be easy as we only have to test the logic.

For instance, we can write the following code to organize our components into a container and presentational component:

import React, { useEffect } from "react";

const Result = ({ result }) => {
  return <p>{result.name}</p>;
};

export default function App() {
  const [result, setResult] = React.useState({});
  const getResult = async () => {
    const res = await fetch(`https://api.agify.io?name=michael
    `);
    setResult(await res.json());
  };

  useEffect(() => getResult(), []);
  return <Result result={result} />;
}

In the code above, App is the container component for Result . Result just displayed what’s passed in from App , while App has the logic to get the data that we want to display in Result by passing the retrieved data via props.

Portals

Portals are a way to render children into a DOM node that exists outside the DOM hierarchy of the parent component. This is convenient for creating things like modals and anything that we want to put outside of the normal DOM hierarchy.

We can create a component that mounts a component in a DOM element of our choice as follows:

index.html :

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />
    <meta name="theme-color" content="#000000" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
    <title>React App</title>
  </head>

  <body>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div>
    <div id="foo"></div>
  </body>
</html>

index.html :

import React from "react";
import ReactDOM from "react-dom";

const Portal = ({ children }) => {
  const domNode = document.getElementById("foo");
  return ReactDOM.createPortal(children, domNode);
};

export default function App() {
  return (
    <Portal>
      <p>foo</p>
    </Portal>
  );
}

In the code above, we have the Portal component that returns:

ReactDOM.createPortal(children, domNode);

The code above mounts our children into the DOM Node of our choice, which is the div with the ID foo .

Then in App , we render the Portal component with the p element with text ‘foo’.

Therefore, we’ll see the word ‘foo’ display on the screen and the p element with that text is a child of the div with ID foo instead of being the child of the div with ID root , which is the mount point of our app.

Code Splitting

By default, a built React app is loaded all at once. This means that no matter how big it is, it’s downloaded and run in the browser as one big package.

Even though lots of people have fast internet now, this may still be a problem for lots of people around the world with slow connections. To make code load in small pieces asynchronously, we can use code-splitting to load a React app in pieces.

We can do code-splitting with Create React App by using the Webpack’s import function and providing a component to load when the actual component is loading.

For instance, we can use the import function, the React.lazy method, and React.Suspense component to create make components load when it’s needed instead of loading immediately as follows:

Foo.js :

import React from "react";

export default function Foo() {
  return <p>foo</p>;
}

App.js :

import React, { Suspense } from "react";
const Foo = React.lazy(() => import("./Foo"));

export default function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Foo />
    </Suspense>
  );
}

In the code above, we moved the component that we want to load on demand into its own module. Then we import it with:

const Foo = React.lazy(() => import("./Foo"));

instead of a normal ES import.

Then in App , we use the Suspense component that’s provided by React and pass a fallback component to show when the component is loading into the fallback prop.

Inside the Suspense component, we put the component we actually want to show inside.

Therefore, we’ll see ‘Loading…’ when Foo is loading, then ‘foo’ is shown.

Conclusion

To make testing and maintenance easy, we should organize our code into container components that have logic and presentation components that are only used to display items.

To mount the React component outside of its usual location, we can render portals to mount our React components anywhere we want.

Finally, to make React load in pieces when it’s needed instead of loading everything at once, we can use code-splitting to load components on demand.

Categories
React

How to Use URL Parameters and Query Strings With React Router

React is a library for creating front-end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

To build single-page apps, we have to have some way to map URLs to the React component to display.

In this article, we’ll look at how to access URL parameters in React Router routes.


Define Routes That Accept URL Parameters, and Get Them

To define a Route with a path that takes an id as a parameter, we can put a colon before the parameter name.

For example, we can write:

<Switch>  
    <Route path="/:id" children={<User />} />  
</Switch>

Then we can use the useParams Hook to get the URL parameter.

We can write a full example as follows:

In the code above, we have the Switch component in App with the Route inside as a child. The path prop is set to /:id , which means that we can use the useParams Hook later to get the route parameter.

Then in the children prop, we pass in the User component, which we want to display.

Also, we added Link components with the links that we can click to go to the URL with the given URL parameters in the to prop.

Then in the User component, we get the id from the URL parameter with the useParams Hook.

Finally, we display the id in the User route.


Get and Set Query Strings

We can define and use a useQuery Hook in a component to get query parameters. To pass in query parameters, we just add them to the Links to props as usual.

For example, we can write the following:

We first defined the useQuery Hook to get the query parameters of the URL via the URLSearchParams constructor. We get the useLocation()s search property.

Then we create a QueryScreen component to call useQuery() and get the URLSearchParams instance assigned to query. This is where we can use query to get the name query parameter by calling get with 'name' passed in.

Then we pass in the value returned by query.get(“name” ) to the User component as a prop and display it there.


Conclusion

We can use the useParams Hook to get a URL parameter defined in Routes.

We can accept URL parameters in a Route by putting a colon before the parameter name in the path parameter, like path=”/:id”.

To add query strings in a path, we just append it directly to the path.

Then we can convert the query string into a URLSearchParams instance, and we can use the search property of that to get the query string.

We can then use the get method with the key name to get the value.