Categories
React Tips

React Tips — Loading Data

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 load data in our React components.

Loading Data When the Component First Loads with the useEffect Hook

If we’re using hooks in React function components, we can load data from an API when the component first loads by using the useEffect hook with an empty array as the second argument.

For instance, we can load data by writing:

import React, { useEffect, useState } from "react";

export default function App() {
  const [data, setData] = useState({});
  const loadData = async () => {
    const res = await fetch("https://api.agify.io/?name=michael");
    setData(await res.json());
  };

  useEffect(() => {
    loadData();
    return () => {};
  }, []);
  return <p>{data.name}</p>;
}

In the code above, we use the useEffect hook to fetch data from an API and then set the result to the data state variable with the setData function.

Then we call the loadData function in the useEffect callback. The 2nd argument of the useEffect hook is an empty array.

React then will rerender the data as the data from the API is fetched. The useEffect callback will only run when the component first loads if the 2nd argument of useEffect is an empty array.

Loading Data When the Component’s Prop Changes

If we pass in the prop variable to the array in the 2nd argument of useEffect , the callback that we pass into the 1st argument will run as the prop changes.

For instance, we can write the following code fetch data from an API as our prop changes:

import React, { useEffect, useState } from "react";

const Name = ({ name }) => {
  const [data, setData] = useState({});
  const loadData = async () => {
    const res = await fetch(`https://api.agify.io/?name=${name}`);
    setData(await res.json());
  };

  useEffect(() => {
    loadData();
    return () => {};
  }, [name]);
  return <p>{data.name}</p>;
};

export default function App() {
  const [name, setName] = useState("");
  return (
    <div>
      <input onChange={e => setName(e.target.value)} />
      <Name name={name} />
    </div>
  );
}

In the code above, we have an input in App , where the inputted value is set as the value of the name variable with setName . Then we have the Name component, which passes the name prop with the value name ,

In Name , we have the useEffect hook which is similar to what we have before. The name prop is passed into the array in the second argument of useEffect , which means that it’s watched.

Note that we returned a function in the useEffect callback. This is used for clean up code. Whenever we have something in the array in the 2nd argument of useEffect , we have to return a cleanup function. Otherwise, we’ll get a ‘destroy is not a function’ error.

Then when we type in something, we’ll see that data is fetched from the API and the data is displayed as the output.

Adding a Loading Indicator in Fetch Calls

We can use the react-promise-tracker package to watch for loading promises and sets a state to indicate that one or more promises are loading.

To use it, we first install it by running:

npm i react-promise-tracker

Then we can use it as follows:

import React, { useEffect, useState } from "react";
import { usePromiseTracker, trackPromise } from "react-promise-tracker";

const sleep = ms => new Promise(r => setTimeout(r, ms));

export default function App() {
  const [data, setData] = useState({});
  const { promiseInProgress } = usePromiseTracker();
  const loadData = async () => {
    await sleep(2000);
    const res = await fetch("https://api.agify.io/?name=michael");
    setData(await res.json());
  };
  useEffect(() => {
    trackPromise(loadData());
    return () => {};
  }, []);

  return <p>{promiseInProgress ? "loading" : data.name}</p>;
}

In the code above, we have 2 promises. One if the sleep function call, which returns a promise. Then we have our fetch request promises in the loadData function.

We then use the trackPromise function from react-promise-tracker to track whether the promises are finished or not.

If one or more promises are loading, then we have the promiseInProgress state is set to true . When it’s true , we show the ‘loading’ text. When the promises are done, we show the value of data.name .

This is a great package that makes tracking the loading of promises easy. We can also add a delay as follows to delay the loading of the promise as follows:

import React, { useEffect, useState } from "react";
import { usePromiseTracker, trackPromise } from "react-promise-tracker";

const sleep = ms => new Promise(r => setTimeout(r, ms));

export default function App() {
  const [data, setData] = useState({});
  const { promiseInProgress } = usePromiseTracker({ delay: 500 });
  const loadData = async () => {
    await sleep(2000);
    const res = await fetch("https://api.agify.io/?name=michael");
    setData(await res.json());
  };
  useEffect(() => {
    trackPromise(loadData());
    return () => {};
  }, []);

  return <p>{promiseInProgress ? "loading" : data.name}</p>;
}

In the code above, we have:

usePromiseTracker({ delay: 500 })

to prevent flickering when the component is loaded on high-speed connections.

Conclusion

In React function components, it isn’t immediately obvious where we place our code to load data. The correct way is to add callbacks to the useEffect hook.

The 2nd argument of useEffect will indicate when the callback will run. If it’s empty, then it’s run when the component first loads. If it’s not, then it’ll watch the value changes of the items in the array and runs the callback when any of them change.

We have to return a cleanup function to run clean up code if needed. Even if we don’t, we still need to return an empty function.

To add a loading indicator when promises load, we can use the react-promise-tracker package to track that and render the loading indicator according to the state returned by this package.

Categories
React Tips

React Tips — Conditionals

React is one of the most popular libraries for creating front end apps. It can also be used to create mobile apps with React Native.

In this article, we’ll look at how to display items conditionally in various ways.

Conditionally Displaying Items

There’re a few ways to display items conditionally with React. We can use conditional statements like if and switch statements. If we’re only toggling between 2 items, then we can also use ternary expressions.

To use ternary expressions, we can write the following code to do that:

import React from "react";

export default function App() {
  const [on, setOn] = React.useState(true);
  return (
    <div className="App">
      <button onClick={() => setOn(on => !on)}>toggle</button>
      {on ? <p>on</p> : <p>off</p>}
    </div>
  );
}

In the code above, we have a toggle button, which when clicked, toggles the on state between true and false .

If on is true , we render ‘on’. Otherwise, we render ‘off’. The following is the ternary expression that we used to do that:

{on ? <p>on</p> : <p>off</p>}

This is great because we don’t have to write if statements to do the same thing, which is much longer.

It’s also an expression, which means that we can embed it in our React code without creating a function unlike if or switch statements.

Therefore, this is much better than using conditional statements if we only display one thing or another based on some condition.

We can write this in an even shorter way if we don’t display anything if on is false .

In this case, we can just use the && operator because it evaluates both operands to see if they both are truthy. If the first operand is falsy, then it’ll just return false instead of evaluating the 2nd operand.

For instance, we can use it as follows:

import React from "react";

export default function App() {
  const [on, setOn] = React.useState(true);
  return (
    <div className="App">
      <button onClick={() => setOn(on => !on)}>toggle</button>
      {on && <p>on</p>}
    </div>
  );
}

In the code above, if on is true then it’ll evaluate the 2nd operand, which is <p>on</p> . Otherwise, it’ll just return false .

Therefore, when on is true , then <p>on</p> will be rendered.

If we have anything longer, then we need to write out the full conditional statement. We should do that in its own function or component.

For instance, if we display more things based on more cases than 2, then we need to write them out as we do in the following code:

import React from "react";

const Fruit = ({ val }) => {
  if (val === 0) {
    return <p>apple</p>;
  } else if (val === 1) {
    return <p>orange</p>;
  } else if (val === 2) {
    return <p>grape</p>;
  }
};

export default function App() {
  const [num, setNum] = React.useState(0);
  return (
    <div className="App">
      <button onClick={() => setNum(num => (num + 1) % 3)}>rotate</button>
      <Fruit val={num} />
    </div>
  );
}

In the code above, we have the Fruit component, which is a stateless component that returns the name of a fruit and displays it in a p element, based on the value of the val prop that’s passed in.

Then in our App component, we have the button, which rotates between the numbers by calling setNum to update the number by rotating them between 0, 1 and 2.

Therefore, when we click the rotate button, we get that we’ll see the name of the fruit rotate between ‘apple’, ‘orange’ and ‘grape’.

Likewise, we can do the same with the switch statement as follows:

import React from "react";

const Fruit = ({ val }) => {
  switch (val) {
    case 0: {
      return <p>apple</p>;
    }
    case 1: {
      return <p>orange</p>;
    }
    case 2: {
      return <p>grape</p>;
    }
    default: {
      return undefined;
    }
  }
};

export default function App() {
  const [num, setNum] = React.useState(0);
  return (
    <div className="App">
      <button onClick={() => setNum(num => (num + 1) % 3)}>rotate</button>
      <Fruit val={num} />
    </div>
  );
}

The code above is longer since we should put a default case no matter if it’s used or not just in case when we run into some unexpected value.

Also, we used case blocks instead of case statements so that we can define block-scoped variables with the same name in each block if needed, so it’s good practice to use it any time.

In the end, we get the same result as before.

If we have if and switch statements in our component, then it’s better to put them inside their own component since they’re long.

Conclusion

There’re many ways to display things conditionally in React components. We can use ternary expressions if we have 2 cases. If we want to display one thing conditionally, we can use the && operator.

Otherwise, we should put if and switch statements in their own component if we need them.

Categories
React Tips

React Tips — Rendering Lists, Dynamic Components, and Default Props

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 render lists in React components, rendering components dynamically, and setting default props.

Rendering Lists

We can render lists by mapping our data to the component that we use to render the list item.

To do the mapping, we use the array’s map instance method. We can do that as follows:

import React from "react";

const persons = [
  { firstName: "Jane", lastName: "Smith" },
  { firstName: "Alex", lastName: "Jones" },
  { firstName: "May", lastName: "Wong" }
];

const Person = ({ firstName, lastName }) => (
  <div>
    {firstName} {lastName}
  </div>
);

export default function App() {
  return (
    <div>
      {persons.map((p, i) => (
        <Person {...p} key={i} />
      ))}
    </div>
  );
}

In the code above, we have the Persons array, which we call map on in App . In the map method, we pass in a callback to return the Person component with all the properties of each persons entry passed in as props.

We need the key prop so that React can identify them properly. Ideally, it’s a unique ID, but the array index can also be the value of the key prop.

Then in Person , we have the props in the parameters and we decompose the prop properties in variables with the destructuring syntax.

Therefore <Person {...p} /> is the same as:

<Person firstName={p.firstName} lastName={p.lastName} key={i} />

It’s a lot shorter if our prop name is the same as our object’s property names.

In the end, we see:

Jane Smith
Alex Jones
May Wong

displayed on the screen.

Dynamic Component Names

React components can have dynamic components. As long as the variable name starts with an upper case, it can be used as a dynamic component. We can render components with dynamic component names as follows:

import React from "react";

const Foo = ({ text }) => <p>{text} foo</p>;
const Bar = ({ text }) => <p>{text} bar</p>;

const components = {
  foo: Foo,
  bar: Bar
};

export default function App() {
  const [name, setName] = React.useState("foo");
  const toggle = () => {
    setName(name => (name === "foo" ? "bar" : "foo"));
  };

  const Component = components[name];
  return (
    <>
      <div>
        <button onClick={toggle}>Toggle</button>
        <Component text="hello" />
      </div>
    </>
  );
}

In the code above, we have the name state, which is set by the setName function. The toggle function calls setName to change the name.

Outside the toggle function in App , we set the Component variable by using:

const Component = components[name];

Then we return the Component to render it. We can pass props to it like any other static component.

Therefore, when we click the toggle button, we should see ‘hello foo’ and ‘hello bar’ displayed as the button is clicked.

Default Props

We can add default props to make sure we always have some values set for our props.

To set default props, we use the defaultProps property to set the default values of each prop;

For instance, we can write the following code to set default props for the Person component that we have above:

import React from "react";
const persons = [
  { firstName: "Jane", lastName: "Smith" },
  { firstName: "Alex", lastName: "Jones" },
  { firstName: "May", lastName: "Wong" },
  {}
];
const Person = ({ firstName, lastName }) => (
  <div>
    {firstName} {lastName}
  </div>
);
Person.defaultProps = {
  firstName: "No",
  lastName: "Name"
};

export default function App() {
  return (
    <div>
      {persons.map((p, i) => (
        <Person {...p} key={i} />
      ))}
    </div>
  );
}

In the code above, we added:

Person.defaultProps = {
  firstName: "No",
  lastName: "Name"
};

to set the default values of the firstName and lastName props.

Then we’ll get the following displayed on the screen:

Jane Smith
Alex Jones
May Wong
No Name

Since we have an empty object in the persons array as the last entry. Therefore, the default values are rendered in place of whatever is passed in.

Conclusion

We can render lists by mapping arrays to components with a map method. In case props aren’t passed into a component, we can set the defaultProps property to set the default values of one or more props.

Finally, we can render components dynamically can map the components by their name string in an object.

Categories
React Tips

React Tips — Data Flow and Pure Components

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 share data between components and speed up rendering with pure components.

Data Flow with Flux

Flux architecture is a way to create a data layer in JavaScript apps. It works by adding the data layer in a centralized data store. Updates to the store are done by dispatching actions to the store which updates the store’s state.

Any component that needs the data can subscribe to the latest updates to the data store to get the relevant state.

This is a good way to organize our data layer structure because it removes the need to share data between components directly. All data is in one place.

This reduces the confusion that arises from sharing data between components, especially if we need to pass data between unrelated components by passing data between a chain of related components.

The most common library for implementing the Flux architecture is with Redux. We can use it by writing the following code:

index.js :

import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import App from "./App";
import { Provider } from "react-redux";

const counter = (state = 0, action) => {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    default:
      return state;
  }
};

const store = createStore(counter);

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  rootElement
);

App.js :

import React from "react";
import { useSelector, useDispatch } from "react-redux";

export default function App() {
  const count = useSelector(state => state);
  const dispatch = useDispatch();

  return (
    <>
      <button onClick={() => dispatch({ type: "INCREMENT" })}>Increment</button>
      <p>{count}</p>
    </>
  );
}

In the code above, we used the React hooks version of the React-Redux API. First, we created the store with:

const counter = (state = 0, action) => {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    default:
      return state;
  }
};

const store = createStore(counter);

Then we wrap the Provider component around the entry point of our app in index.js . We pass in the store object so that we can access it.

The store is created by first creating the counter reducer, which updates the state . Then we pass in the counter reducer to createStore to create the store.

Then in App , we access the store by using the useDispatch hook so that we can dispatch actions with the returned function. Then we use the useSelector hook to return the state from our store with the callback.

Once we did that, we call dispatch when we click the Increment button. In the dispatch function call, we pass in the type property with the 'INCREMENT' action, which means that the 'INCREMENT' action in the counter reducer will be completed.

Then when we click the Increment, count will update because we updated the store with state + 1 each time the 'INCREMENT' action is dispatched.

Pure Components

Pure components are React components that implement the shouldComponentUpdate method.

The ones that implement shouldComponentUpdate are always class-based components. We can also create components that don’t implement that by returning the result that is derived from the props that are passed in.

In general, a component is pure if the return value of the component is only determined by its input values.

We can create a classed based component and use it as follows:

import React from "react";

class Pecentage extends React.PureComponent {
  render() {
    const { score, total } = this.props;
    return (
      <div>
        <span>{Math.round((score / total) * 100)}%</span>
      </div>
    );
  }
}

export default function App() {
  return <Pecentage score={70} total={100} />;
}

In the code above, we have the Percentage component, which implements React.PureComponent .

It takes 2 props, score and total and we return the percentage point derived from score divided by total .

shouldComponentUpdate is automatically included and it does a shallow comparison of the data, so we don’t need to write one ourselves to do the comparison since both props are numbers. Therefore, React will rerender the component only if the props change in value.

On the other hand, if the props are objects, then we’ll need to implement the method and do the checks ourselves.

It returns the same output given the same input, so it’s a pure component.

Also, we can implement pure function components as follows:

import React from "react";

const Pecentage = ({ score, total }) => {
  return (
    <div>
      <span>{Math.round((score / total) * 100)}%</span>
    </div>
  );
};

We just pass in the props as we need to and it also returns the same output given the same input, so it’s a pure component.

Conclusion

If our apps have multiple components that need to share data, then we need Flux architecture. To implement it, the best way is to use popular existing libraries like Redux.

The pure component has optimizations that are done by React to speed up rendering. They only render if the props change. The change detection is done by shallow comparison.

Categories
React Tips

React Tips — Components and Props

React is one of the most popular libraries for creating front end apps. It can also be used to create mobile apps with React Native.

In this article, we’ll look at the basics of React that we may have missed or forgotten.

Components Can Be Reused Anywhere in Our App

The whole point of creating a React component is that we create a group of elements and components that we can use anywhere in our app.

For instance, we can define our components and use them anywhere as follows:

import React from "react";

const Foo = () => <p>foo</p>;
const Bar = () => <p>bar</p>;

export default function App() {
  return (
    <div className="App">
      <Foo />
      <Bar />
      <Bar />
    </div>
  );
}

In the code above, we created the Foo and Bar components, which we used in our App component.

We can reference them as many times as we want. Although if we reference them more than twice we should use the map method to return multiple instances of a component instead of repeating them everywhere.

For example, if we want to show the Bar component 5 times in App, we can write the following code:

import React from "react";
const Bar = () => <p>bar</p>;

export default function App() {
  return (
    <div className="App">
      {Array(5)
        .fill()
        .map((_, i) => (
          <Bar key={i} />
        ))}
    </div>
  );
}

In the code above, we created an array, fill them with undefined with filland then map all the entries to Bar so that we can display Bar 5 times.

Also, we always have to remember to set the key prop so that React can identify them properly. The key prop’s value for each entry should be a unique value like the array index or another unique ID.

Data Can Be Dynamically Passed to Components with Props

Without props, most components are useless since almost all of them need data for them to be useful.

For instance, we can create a component that takes a prop and use it as follows:

import React from "react";

const names = ["jane", "joe", "alex"];

const Name = ({ name }) => <p>{name}</p>;

export default function App() {
  return (
    <div className="App">
      {names.map((n, i) => (
        <Name key={i} name={n} />
      ))}
    </div>
  );
}

In the code above, we created the Name component which takes the name prop and display it inside the component.

Then we used it by calling map on names to map them name strings in the array into the Name component to render it.

We passed in the name prop with the value n from the names array so the the name property will be populated by the name string from the array.

Therefore, we’ll see:

jane

joe

alex

displayed on the screen.

If we have multiple props, we can use the spread operator to spread them all into props so that we don’t have to write them out all at once.

For instance, we can write the following to spread our props into a component as follows:

import React from "react";

const names = [
  { firstName: "jane", lastName: "smith" },
  { firstName: "john", lastName: "smith" },
  { firstName: "alex", lastName: "jones" }
];

const Name = ({ firstName, lastName }) => (
  <p>
    {firstName} {lastName}
  </p>
);

export default function App() {
  return (
    <div className="App">
      {names.map((n, i) => (
        <Name key={i} {...n} />
      ))}
    </div>
  );
}

In the code above, we have the names array, which has the firstName and lastName properties.

To make our code shorter when we are passing props into the Name component, we spread the properties of each entry as props by using the spread operator as we did in:

<Name key={i} {...n} />

As long as the property and prop names match exactly and in the name nesting level, then they’re spread as props properly.

Since firstName and lastName are all at the top level, we can spread them easily with the spread operator and they’ll be the value of the props with the same name.

Conclusion

React components can be anywhere in our app. They can be referenced as long as they’re defined.

We can pass in data to components via props. This makes them useful. We can pass in props by passing them explicitly in a way that looks like their HTML attributes, or we can use the spread operator to pass in multiple props with the same name all at once.