Practical React & Redux - Part 1

David Morcillo - Apr 24 '20 - - Dev Community

Originally published at Codegram's blog

At Codegram we can spend 5 hours a week doing some learning stuff like reading books, doing an online course, or even crafting some pet project to try a new technology. It's really cool and sometimes we even share with our coworkers what are we doing in our biweekly Codegram's Talk Club™️. We want to make a step forward and we decided to create a new learning resource: introducing Codegram's Workshops™️!

Today we are gonna talk about React and Redux. In this first article of this workshop series we are gonna learn how to bootstrap a React application and create our first components. Stay tuned for future updates in this workshop series and let's start!

Introduction

This course is an introduction to React and Redux. We are gonna learn how to create a react application from scratch and deal with components and their weird JSX syntax.

This is not a complete React course and I want to focus on the basics and how to work with a store. I am not gonna cover some topics like styling your components or testing because these are broad topics that can be covered in future workshops. Even though we are gonna use Webpack I am not gonna cover any complex setup either. Let's begin!

Getting started

First of all we need a React application to start working on! There is a package called create-react-app that is very useful to bootstrap something. You can run this command:

$ npx create-react-app --use-npm practical-react-and-redux

By default the command uses yarn but I prefer npm. Let's move to that directory and start the development server:

$ cd practical-react-and-redux
$ npm start
Compiled successfully!

You can now view practical-react-and-redux in the browser.

  Local:            http://localhost:3000
  On Your Network:  http://192.168.1.12:3000

Note that the development build is not optimized.
To create a production build, use npm run build.

This will open your browser automatically to http://localhost:3000 and if you see the React logo spinning then the application has been compiled successfully and we are ready to start doing some stuff!

Spin up your favorite editor and move on 👏

Components are just functions

Let's start our journey creating our first component but, first of all, what's a component? In the React world a component is just a function that returns something that can be rendered in our DOM. Open the src/App.js file and remove everything.

Hello world components

We are gonna create our first component: the App component. Every React application has a root component and although you can name it whatever you want it is usually named App or Application (notice the CamelCase syntax). Write this in your src/App.js file:

// src/App.js
const App = () => {
  return 'Hello World!'
}

export default App

If you visit the http://localhost:3000 you will see our message. Congratulations you just write your first component! 🎉

You are not limited to just Strings and you can also write plain HTML in there. Try this:

// src/App.js
const App = () => {
  return <p>Hello world!</p>
}

export default App

Oh snap! Our application is not working anymore and we got a compilation error. What did you expect? Do you think that looks like JS? Of course not!

There is so magic ✨ behind of this. First of all we are not using plain JS anymore and we started using jsx. That's a language that compiles to JS and you can think about it as a hybrid between JS and XML (or just HTML).

In order to make that work we need to bring React to the party so let's import it!

// src/App.js
import React from 'react'

const App = () => {
  return <p>Hello world!</p>
}

export default App

You might be thinking: why I am importing the React constant if I am not using it? That's true! We are not using the React constant explicitly but when Webpack compiles this jsx it's using React.createElement under the hood to create our component so we need to bring that constant to make it work. If you are curious you can check the main.chunk.js source file in the browser.

A single component is really boring so let's create a few more components!

Components hierarchy and reusability

Time to create a Dog 🐶 component! As you may notice there is no folder structure to follow but I like to stick to some conventions. I like to organise my components per feature and also having each component in its own folder:

$ mkdir -p src/dogs/components/dog

In your editor create the Dog.js file in the new folder that we just created with the following content:

// src/dogs/components/dog/Dog.js
import React from 'react'

const Dog = () => {
  return (
    <div>
      <p>Boira</p>
      <p>Score: 13/10</p>
    </div>
  )
}

export default Dog

Now we can use this component in our App component like this:

// src/App.js
import React from 'react'
import Dog from './dogs/components/dog/Dog'

const App = () => {
  return (
    <>
      <Dog />
      <Dog />
    </>
  )
}

export default App

You might be wondering what's that ugly thing: <>. That's an empty tag and we need that for two reasons:

  • Every React component needs a single root element.
  • We don't want extra markup so the <> root element is not gonna render anything

Then we are just rendering two Dog components. As you can see a component can be used as a simple DOM element. We are enhancing the HTML language adding new tags!

Having two dogs named after my dog Boira is cool but it is cooler if we can change dynamically some things in our components. Enter the props!

Dynamic components using props

A prop or a property is a component's input data. Remember: components are just functions so props is just the single argument that our function is receiving. Since it is an Object we can use destructuring like this:

// src/dogs/components/dog/Dog.js
import React from 'react'

const Dog = ({ name, score }) => {
  return (
    <div>
      <p>{name}</p>
      <p>Score: {score}/10</p>
    </div>
  )
}

export default Dog

We added the two props: name and score. We are also using those variables inside our template escaping the value using curly braces {}.

If you refresh the page right now you are gonna see nameless dogs without score and that's very sad. You can think about props as a object that include all HTML attributes given to the DOM element representing your component. In other words, you can set the element of these props giving attributes to the <Dog> tag:

// src/App.js
import React from 'react'
import Dog from './dogs/components/dog/Dog'

const App = () => {
  return (
    <>
      <Dog name="Boira" score="13" />
      <Dog name="Black" score="13" />
    </>
  )
}

export default App

The application works and we have two different dogs now! There is one problem with our current implementation: we could forget to give a value to the score prop and a dog could end having a null score 😱.

Props validation: avoid bugs

React doesn't include a built-in package for props validation but there is a package called PropTypes that is included by default when we created the application. We can use this package to validate our props and ensure our components are used correctly:

// src/dogs/components/dog/Dog.js
import React from 'react'
import PropTypes from 'prop-types'

const Dog = ({ name, score }) => {
  return (
    <div>
      <p>{name}</p>
      <p>Score: {score}/10</p>
    </div>
  )
}

Dog.propTypes = {
  name: PropTypes.string.isRequired,
  score: PropTypes.number.isRequired
}

export default Dog

If you reload the app the application, it is working but we have an error in our console 🤔. We just found a bug! 🐛. In the previous snippet we added prop validations and marked both props as required. We also marked our score as a number but we are giving it as a string right now. Let's fix this:

// src/App.js
import React from 'react'
import Dog from './dogs/components/dog/Dog'

const App = () => {
  return (
    <>
      <Dog name="Boira" score={13} />
      <Dog name="Black" score={13} />
    </>
  )
}

export default App

The change might be a bit subtle: we replaced "13" with {13}. Since we are using curly braces again we are evaluating that 13 as a Javascript numberand the error is gone!

Event handlers as props

New requirements: we want to add a button to increase that score (we are not gonna add a button to decrease it because dogs are awesome). We need to listen to the click DOM event for a button and lucky for us React supports a onClick prop. Let's see how this works!

// src/dogs/components/dog/Dog.js
import React from 'react'
import PropTypes from 'prop-types'

const Dog = ({ name, score }) => {
  const onClick = () => {
    score += 1
    console.log(`This is your new score: ${score}`)
  }

  return (
    <div>
      <p>{name}</p>
      <p>Score: {score}/10</p>
      <button onClick={onClick}>Increase score</button>
    </div>
  )
}

Dog.propTypes = {
  name: PropTypes.string.isRequired,
  score: PropTypes.number.isRequired
}

export default Dog

Don't click the button yet! Let's check the code first. We added a new button element to the template and added the onClick prop. That prop needs to be assigned to a callback function that will be called when the user presses the button. I added a new function called onClick (naming is hard sorry) and I am increasing the score prop and logging a message.

If you visit the page and click the button you will see the message prompted in your console with the new score value. Yeah you did it! Oh...wait. The template is not being updated, we have another bug! 🐛

Not really 😅, props are supposed to be read-only and our Dog component is stateless. We need to make our component stateful to be able to change that score!

Just a quick warning ❗️: When a component's prop changes the component is automatically re-rendered but in our case we are not really changing the prop so the view is not updated.

Conclusion

In this article we learned about how to create a React application from scratch and added our first components. In the next article we are gonna learn about stateful components using React hooks and also we are gonna do our first steps with Redux.

You can find the code examples in this repository. I also tagged the progress for part 1 in case you want to check the repository at this specific moment.

Cover photo by Lachlan Donald

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