Next.js Global State w/ React Context API

The easiest way to implement global state management in your Next.js application is the React Context API.

I made a new file called ContextProvider.js and created a Context object called MyContext:

import React, { useState, useContext, useEffect } from 'react';

const MyContext = React.createContext();

export function useMyContext() {
    return useContext(MyContext);
}

export function MyProvider({ children }) {
    const [myValue, setMyValue] = useState(false);

    return (
        <MyContext.Provider value={{myValue, setMyValue}}>
            {children}
        </MyContext.Provider>
    );
}

Once this is done, go back to pages/_app.js and wrap your component with the context provider:

import { MyProvider } from '../contexts/MyProvider';

function MyApp({ Component, pageProps }) {
    return (
        <MyProvider>
            <Component {...pageProps} />
        </MyProvider>
    );
}

export default MyApp;

Now I can use the state within MyContext in every part of the application.

Make sure to be careful about how much you put into Context. You don’t want unnecessary re-renders across pages when you could just share them across specific components.

React State Management with the Context API

Component-level state is the state within an individual component. It is only available to that component and only affects that component. We can use hooks such as useState to control component-level state.

But what if you want a piece of state to be available to multiple different components or all of your components? This is what we call application-level state.

Application-level state is the state that is available to the entire application. In order to implement this type of state, we need to implement more complex solutions.

One solution would be to “lift up” the state. This involved moving the piece of state to your App component, the root component which holds all of the other components. While this is a bit simpler to implement than other solutions, the problem with it is that you are giving the App component state that it doesn’t directly need and you will have to pass down the state to each component in a very long-winded way. This is called prop-drilling.

Instead, we can use the Context API as a more dynamic and versatile solution. Here’s an example of how it would be used:

Context File

import React, { useState, createContext } from 'react';

export const MyContext = createContext();

export const MyProvider = props => {
   const [property, setProperty] = useState('Initial state of property');

   return (
      <MyContext.Provider value={[property, setProperty]}>
         {props.children}
      </MyContext.Provider>

App File

import React from 'react';
import { MyProvider } from './MyContext';

function App() {
   return (
      <MyProvider>
         <div>
            <MyComponent />
            Other Components...
         </div>
      </MyProvider>
   );
}

Component File

import React, { useState, useContext } from 'react';
import { MyContext } from './MyContext';

const MyComponent = () => {
   const [property, setProperty] = useContext(MyContext);

   return (
      <h1>{property}</h1>
   );
};

export default MyComponent;

The downside to the Context API is every time we update the code in our Context, all the components that use the context have to re-render.

The benefits are that it’s more simple than Redux and doesn’t require any third-party libraries.

What is React.js?

React.js is a JavaScript library for building user interfaces. It is a front-end web framework. React.js breaks down the user interface into customizable components. It combines pieces of HTML, CSS, and JavaScript in each component. It allows the browser to refresh a single component without having to refresh the entire page. It is one of the most popular and in-demand web frameworks

Most people put all of their body content within a div with the id “root.” This is React convention.

<div id="root">
</div>

Before we can start coding, we must install our dependencies

npm i react react-dom
ReactDOM.render(WHAT TO SHOW, WHERE TO SHOW it, optional callback after render function completed)
var React = require("react");
var ReactDOM = require("react-dom");

ReactDOM.render(<h1>Hello world!</h1>, document.getElementById("root"));

React works by creating these JSX files. HTML is inputted into compiler which converts it into Vanilla JavaScript. The compiler comes from including the React module.

Inside the React Module, there is something called Babel. Babel is a JavaScript compiler. It’s able to take next-gen JavaScript (es6, es7, es8) and compile it down to a version that any browser can understand. This includes compiling JSX into plain JS.

var h1 = document.createElement("h1");
h1.innerHTML = "Hello World!";
document.getElementById("root").appendChild(h1)
import React from "react";
import ReactDOM from "react-dom";

Render method can only take a single HTML element. If you put two back-to-back, it will crash. The way around this is wrapping n elements into a div, so that it’s “1 element.”

ReactDOM.render(
<div>
   <h1>Hello world!</h1>
   <p>This is the first paragraph.</p>
</div>, 
document.getElementById("root")
);
const name = "Joshua";

ReactDOM.render(<h1>Hello {name}!</h1>, document.getElementById("root"));
const num = 4;

ReactDOM.render(<p>Your lucky number is {num}!</p>, document.getElementById("root"));
ReactDOM.render(<p>Your lucky number is {Math.floor(Math.random() * 10)}!</p>, document.getElementById("root"));

You can add any JavaScript value or expression inside the curly braces, but you can’t write JavaScript statements(if statements, etc.)

Styling

External Stylesheets

<h1 class="heading">Title</h1> // no 
<h1 className="heading">Title</h1> // yes

Although it looks like HTML, it’s JSX. It’s being converted to Vanilla JavaScript. There is no “class” property in JS; the correct JS equivalent is the className property.

HTML uses all lowercase. When we write JSX we use camel case because JS uses camel case.

contenteditable vs contentEditable

<h1 contentEditable="true" spellCheck="false">My Favourite Foods</h1>

It is recommended to do all of your styling in an external CSS file then apply those styles to your JSX content with class and id tags.

.heading {
   color: 'red';
}
<h1 className="heading">My Favorite Foods</h1>

Inline Styling

The style property requires a JavaScript object

JavaScript object

{
  key: value,
}
<h1 style="color: 'red'">My Title</h1> // no
<h1 style={{color: 'red'}}>My Title</h1> // yes

Any JavaScript within HTML must be wrapped in curly braces. JavaScript objects must be wrapped in curly braces. Thus, 2 sets of curly braces

const customStyle = {
  color: "red",         // use commas instead of semicolons
  fontSize: "20px",     // font-size becomes fontSize
  border: "1px solid #000" // every value goes in quotes
}

customStyle.color = "blue";  // change styles after definition

ReactDOM.render(
  <div>
    <h1 style={customStyle}>My Favourite Foods</h1>
  </div>,
  document.getElementById("root")
);

React Components

We always capitalize the names of our components because that’s how React differentiates that they are custom components

function Heading() {
   return <h1>My Heading!</h1>
}

ReactDOM.render(
   <div>
      <Heading />
   </div>,
   document.getElementById("root")
);

In the same folder, create a new file called “Heading.jsx”

All of our components separated into individual files with the .jsx extension

import React from "react";

function Heading() {
   return <h1>My Heading!</h1>;
}

export default Heading;

Don’t use parentheses. That will make it run immediately; we want to use it as a component

import React from "react";
import ReactDOM from "react-dom";
import Heading from "./Heading";

Most times, you won’t see any div or child elements in the index.js file. Instead, it will just be a single App custom component.

import React from "react";
import Heading from "./Heading";   // child component
import List from "./List";         // child component

function App(){
   return <div>
      <Heading />
      <List />
   </div>
}

export default App;
ReactDOM.render(
   <App />,
   document.getElementById("root")
);

Create a components folder and put all of your components in it

  • src
    • components
      • App.jsx
      • Heading.jsx
      • List.jsx
  • public
    • index.html
    • styles.css
import App from "./components/App";

Setup React Front-End in Existing Project

Let’s say you’re building with the MERN stack, for example. You have an existing project folder in which you’ve set up your entire backend server with Express and connecting your MongoDB database. Now you want to append a React frontend to the project. How do you setup a new React project within your existing overall project folder?

cd into your existing project folder and run this command:

npx create-react-app [your-folder-name]

This line basically creates a React application within a folder with whatever name you choose (ex. client) within your current project directory. npx is a tool that comes with Node.js that allows us to run create-react-app without having to install it globally on our machine.

To run your React project to make sure everything installed successfully, run these commands:

cd [your-folder-name]
yarn start

Run Frontend and Backend at the Same Time

We can run our frontend React app and backend Node.js server at the same time using the development tool concurrently.

Install concurrently as a development dependency:

npm i -D concurrently

Define the necessary scripts within your package.json:

"scripts": {
    "start": "node server",
    "server": "nodemon server",
    "client": "npm start --prefix client",
    "dev": "concurrently \"npm run server\" \"npm run client\""
},

The “dev” script uses concurrently to run the “server” and “client” scripts at the same time– with one single command.

In the root folder, run the “dev” script:

npm run dev

Installing Dependencies Within the React Project

You install dependencies within a submerged React project the same way you would within an non-submerged React project.

First, make sure you’re inside the React project folder. My folder name is client so:

cd client

Then, install dependencies with npm

npm i react-redux axios ...

Get Ride of Default Git Repository Within React App

Within the React app, a git repository is automatically initialized on the creation of the React app. If you already have a Git repository within your root project, you don’t necessarily need another one for your React project. If you wanted to delete the React repository, you would

  1. Delete the .gitignore and README.md files within the React folder
  2. Delete the Git folder

This is the command to delete the git folder. Make sure you cd into your React folder before running this command or you might delete your root repository:

rm -rf .git

Event Handling in React

This is the App.jsx file. You would render an App Component in the ReactDOM.render method inside the index.js file. You can create your own HTML pages and CSS styles.

import React, { useState } from "react";

function App() {
   const [isMousedOver, setMouseOver] = useState(false);

   function handleMouseOver() {
      setMouseOver(true);
   }

   function handleMouseOver() {
      setMouseOver(false);
   }

   return (
      <div>
         <button
            style={{ backgroundColor: isMousedOver ? "black" : "white" }}
            onMouseOver={handleMouseOver}
            onMouseOut = {handleMouseOut}
         >
            Hover
         </button>
      </div>
   );
}

export default App;

State in React

State is a React concept that allows us to make our apps more interactive and mutable.

React components has a built-in state object. 

The user interfaces re-renders based on the value of state variables.

Declarative programming: the use of variables such as state to change an object’s property

Imperative programming: explicitly setting an object’s property

Imperative programming is about how a program works while Declarative programming is about what a program does. 

Using regular variables to declaratively change the user interface of a React component will not work. You need a special kind of variable in order to cause React elements to re-render: State variables. You also need special functions called Hooks that look– or hook— into the state of your app to read and modify it.

You use the useState hook in order to get access to the component’s state.

import React from "react";

function App() {
   const state = React.useState();
}

Whatever we put into the parentheses of the useState function is the initial state of the component.

const state = React.useState(123);

If we wanted to access the state variable we just created, we would extract the first element of the state array:

console.log(state[0])
// prints out 123

Whenever you change state, React updates any UI elements corresponding w/ that piece of state automatically.

Using state[0] to access state variables is kind of unintuitive though and not the most efficient way to code. So we can use destructuring to make it easier on us as programmers:

const [count] = useState(123);

console.log(count);
//prints 123

How do we change the value of state variables?

const [count, setCount] = useState(123);

setCount(count - 1);

console.log(count);
// prints 122

React Conditional Rendering with the Ternary Operator & AND Operator

JSX only allows you to use JavaScript expressions within curly braces. It does not allow you to enclose JavaScript statements.

So if you wanted to use a condition to decide which content to render on the screen, you COULD NOT use a statement like this:

return <div>{
   if (isLoggedIn === true){
      return <h1>My Favorite Foods</h1>
   } else {
      return <p>My Least Favorite Foods</p>
   }
}</div>;

Instead, you would have to use a ternary operator. This is how ternary operators work:

condition ? do if true : do if false
foodAtHome === true ? makeFood() : buyFood()

So this is how you would accomplish the task from above:

return <div>{
   isLoggedIn === true ? <h1>My Favorite Foods</h1> : <p> My Least Favorite Foods</p>
}</div>;

Another way you can incorporate logic into your JSX objects is with the AND operator. The AND operator in React checks if the first condition is true or false. If true, it looks to see if the expression is also true then displays the expression. If the statement is false, it will not even look at the expression.

condition && expression
true && expression
false && -expression-

Here’s an example of the AND operator:

return <div>{
   currentTime > 12 && <h1>It's not the morning</h1>
}</div>;

Mapping React Components

We can use the JavaScript map function to make our code a lot cleaner when creating multiple components of the same type from a JSON-type data source.

So instead of having something like this:

function App() {
   return (
      <div>
         <Card 
            name={contacts[0].name}
            img={contacts[0].img}
            tel={contacts[0].phone}
          />
          <Card 
            name={contacts[1].name}
            img={contacts[1].img}
            tel={contacts[1].phone}
           />
          <Card 
            name={contacts[2].name}
            img={contacts[2].img}
            tel={contacts[2].phone}
           />
         ...

We can use something like this:

function createCard(contact) {
   return <Card name={contact.name} img={contact.img} />
}

function App() {
   return (
      <div>
         {contacts.map(createCard)}
         ...

We still have something to fix though. Once you run your new code, you should get this warning:

This is because we don’t have a key prop in our child components. The key must be unique among each of the mapped components.

function createCard(contact) {
   return <Card 
      key={contact.id}
      name={contact.name} 
      img={contact.img} 
   />
}

The key CANNOT be used as a property in the component’s props array. The key is for React to use, not us.

How to Set up React DevTools on Google Chrome

Sometimes it will make sense to have components within components. Or components within components within components. Over time, if you accumulate a lot of properties and components, it can be hard to keep track of everything. React DevTools can help with that.

React DevTools show your React DOM tree.

How to Install React DevTools

  1. Open Google Chrome
  2. Go to https://chrome.google.com/webstore
  3. Search and open “React Developer Tools”
  4. Press the “Add to Chrome” button

Once it is done installing, you should see a new symbol show up next to your search bar

How to Use React DevTools

  1. Open up Chrome Developer Tools (View > Developer > Developer Tools)
  2. Open the Components tab
  3. You should see your React DOM tree

How to Fix Problems w/ create-react-app

Possible Problems

You run npx create-react-app my-app and it only tells you npx installed without generating a new project.

You successfully create a new React project but there’s no server.js file in the project. It may give you this error when you run npm start: “missing script: start”

Solution

Installing create-react-app globally is now discouraged. Instead uninstall globally installed create-react-app package by doing:

npm uninstall -g create-react-app

Then, just try creating a new React project:

npx create-react-app my-app