Components, Props and State in React
The main concept of React you need to understand is Components, a component in React are like the tags in HTML, a way to encapsulate code within a single element which has its own functionality, stylization and structure. They allow us to organize our application, sorting it in little pieces that when connected, form the application or in the most case, a piece of it.
Components
We have two ways to define components, first is creating a Javascript function (Fig 1) and the other way is using ES6 class (Fig 2). Both codes are valid React components and will return the text “My First Component”. The return of a valid React component always will be the HTML that you want to display in the browser.
To help you follow the steps in this article, i create a “cleaned” project with only the files that we need to run a React project.
You will need to have git installed in your machine, after that, just go to the terminal in the directory that you want to clone the project and enter this command: ```git clone https://github.com/Verdant31/Cleaned-React-Project``.
If you wanna know better what files i removed, you can check this article here in medium:
For this study, we are going to create a list of repositories, the first component will be a simple HTML list with a strong as the title, a p as description and a link to the repository. To create our component, go on src, create a folder components and inside that create a file called “RepositoryList.js” (Fig 3).
With our component created, we need to tell React that we want to render it, to do that, just go to the App.js file, import our component, remove the previous content and pass our new component to the return (Fig 4). Now going to the root of our application we can see our repositories list (Fig 5).
Every time i say "render", understand as "showing into the browser".
At the moment we have only one repository, but if we have a lot more? Thinking about this, we can create a new component called RepositoryItem(Fig 5) and replicate it in our repositories list (Fig 6).
Our “RepositoryItem” component are with static content, but if i want to pass different informations for each repository? I would need to create one component to each repository? That’s would be a lot of work, to handle that, we can use the props.
Props
Components can receive a single object in the parameters definition, this object is called “props”. You can see them like the attributes that the HTML tags receive, they are variables or information that we can pass to a component to change its behavior.
First, let’s create an array of two repositories and then pass that to our RepositoryItem (Fig 7).
// Creating a variable to store our repositoriesconst repositories =
[{ name: 'The React Universe', description: 'A study of React', url: 'https://github.com/Verdant31/Cleaned-React-Project' }, { name: 'Unform', description: 'Forms in React', url: '/'}]
To clear it out, we create an array with two repositories, which one is an object with name, description and url. With our array created, with passed the first repository to our first RepositoryItem and the second repository to our second RepositoryItem.
Now, we need to receive this props in our RepositoryItem, to do that, how we receive the information in the component as a single variable, the repository object will be inside the props of our component.
We can confirm this by giving a console.log(props) inside our component (Fig 8), the result will be our repository informations in the console of the browser (Fig 9).
We can see that the two rendered components showed it own repository information, one printed the information about the first repository and other printed the second.
To make our component start showing the repositories, we can pass the variables that are inside our repositories to the respective HTML element (Fig 10).
Don't forget that in Fig 7 we are passing our repository as an object named repository, so to access the name, description and URL we need to access the props variable and inside it we will have our repository object. (So, props.repository.repositoryProp).
After this, we already can see the results in the components display (Fig 11).
And that's how we use props in React, now we can pass for the last least thing you need to know to use React, state.
State
To better understand states in React, let’s create a component just to explain this concept, after we will apply it in our repository list. Our component will be a counter (Fig 12), it will have a button to increment the counter and a h1 tag displaying it value.
With the counter created, we can render it by just adding in our App.js file (Fig 13). React doesn’t allow us to pass two or more components in a row without a parent component, so we will use a Fragment (Fragment is just a HTML tag without name, that allow you to wrap or group multiple elements without adding an extra node to the DOM) to handle this.
Let's transform our counter into a functional counter (At the moment, it's doing nothing). To do that, in our component we will create a variable counter that will store the value of our counter and a function called increment to increase it value (Fig 14).
Looking to our code, it has everything to works fine, we have a h1 to display the counter value and a button that when its triggered, call a function to increase the counter value.
But for our surprise, when we click the button, the counter value doesn't change (Or at least that’s what it seems). Let's understand what is going wrong.
Let's give a console.log() inside our function to show what's happening with the counter value (Fig 15).
Now, if we open the developer tools on browser and click the button to increment the counter, we will see that actually the value is changing according we call the function (Fig 16), but why is the value in the browser not also increased?
By default React doesn’t stays listening for changes in variables to re-render a component, and that is understandable. In an application with a lot informations to display in screen, this “feature” it would make the application very slow and cause performance problems. To handle that, React brought the concept of state.
State are the variables that React will monitore to know when re-render and when not. With that in mind, we can conclude that changes in the state of a component causes a re-render. To declare a new state variable, we can use the useState hook from React.
This hook receives the initial value of the state and returns an array with a variable that will store the value itself, and a method to change the state value. By an convention of the community, we always destructure the return of this hook and name the method as set + the variable name, like this:
const [ variableValue, setVariableValue ] = useState(initialValue)
Think in the setVariableValue as a function that receives the new value, creates a new variable passing that new value this new variable and its thats new variable starts to be the new value of that state.
Wouldn't be easier to just directly changes the variable value instead using this method? Yes, would be, but that go against the principle of immutability in state of React.
If you wanna know more about immutability in React, i recommend reading this article:
To make our counter variable a state of our component, we will import useState and use it to create the variable. Now, instead of directly changing the value of counter in our function, we can use the setCounter to do this by calling it and passing the new value that we want to store (Fig 17).
Doing this, when we click the button, we can see that now the counter value is changing, that’s happening why now when we click the button, we are causing a change in the state of our component, forcing React to generate a new render.
Now, going back to our repositories, we can store are repositories in the state of our component just doing this (Fig 18):
Bonus (Creating a function to add a new repository)
To do that, instead of passing the index of the repository to each component, let's make a map in our array of repositories inside the HTML return of our component.
To write Javascript code inside HTML, just put our JS code inside brackets (Fig 19).
Doing this, we ensure that will have a RepositoryItem being render in the browser for each repository in our array. (Same way as before but now more performatic).
Now, we can create a button too trigger a function that adds a new repository to our list (Fig 20).
Note that when we click the button, we can see the new repository being added in the browser, thats why how our repositories are part of the state of our component, when we causes a change (Like, adding a new repository by doing setRepositories([…repositories, newRepository])), we generate a re-render of our component with the new list of repository.
If you wanna see the final project, i will put a link below if the code that we built in this article.
I hope this article helped you somehow in your study of React universe, any suggestion is welcome, thanks for your attention and never forget, don’t stop learning.