This post will focus on data used with React components. If you are new to React and never used it, go and read first part
(https://dev.to/chriss/intro-to-react-without-code-part-1-23h1) of this tutorial where you can discover what React and React components are.
It is possible and perfectly fine to make components with hardcoded data inside of them. There are use cases for it. This could be an image component that always shows the same image and encapsulates the CSS rules for it. More often, component will render the output based on some data either internal component data, or external data. Internal data is what we call state, and data that that is passed to a component is props.
As I already mentioned, state is the internal component data. That means this data is crated and maintained in the component.
To better understand what component state would be, let’s start with an example. We could be building a Counter component that shows how many times a button in the component was clicked. This data is highly connected to the component and only the Counter component should be aware of the counter value. A parent component doesn’t need to know of this value. For that reason, this belongs to the component state.
These values can only be changed in the component that created them, in this case, in the Counter component. They can be passed to a child component that can use them, but the child components can’t modify them.
Props are values that are passed to component. As mentioned at end of previous part, components can’t make changes to this data, just read them.
There are many reasons why we would want to use props instead of state. Maybe we want to split component into smaller pieces, maybe we have some logical layer on top that we want to isolate or maybe we have some reusable piece we want to exclude. But to explain clearer what props are, I will use an example of a phonebook.
We could have a PhoneBook component that contains a list of contacts in its state. What we could do, is have a loop that would add a block of code containing a contact’s details. Another way of structuring it would be instead of having only a PhoneBook component we could also have a Contact component. This Contact component would have common styling and structure for displaying the contacts details. However, the display will be different for each contact e.g. name, phone number, etc. This is information which is contained in the PhoneBook component. Now we can have PhoneBook using the Contact component and passing the contact details through props for rendering.
As previously mentioned, a component can’t change props, but props can be anything. Including function. And some of those passed functions could change prop somewhere up the tree. This could be a good solution when it comes to one level of difference, like our example of PhoneBook and Contact. However, when it comes to more levels, it can become very messy.
Each time props or state changes, the component will re-render. However, this differs depending on if it is a prop or a state value that gets updated.
If we are updating a state, we need to use a specific function provided with React. Once we execute this function to set the new value, React knows this component needs to be re-rendered. If we modify this value in any other way, it would not work.
If props are changed, we don’t need to do anything, React will figure out on its own that it needs to be re-rendered. But for optimization sake, when checking for updates, it won’t do deep checking. It checks only references. This means that if we are passing an object, and change just one property of it, a component receiving this object won’t update. What we need to do to trigger the re-rendering is create a new object that is a copy of the original one with this one property changed.
There is always discussion what belongs to state and what should be passed as props. Truth is there is no universal answer to this question, and it depends on the situation.
We could look at the previously mentioned Counter component. This Component sounds very simple, a Component containing a number and a button that increments the value of that number. There is no need to have data anywhere outside of this component. What could complicate it a bit would be if we needed some special design for displaying the number. It could have some animation on change and shiny effects. Since now we have a more complex design, we might want to split the value display into a new reusable component CounterValue. Now this component just receives the number as a prop to display.
In this case we still have all the data binded to the Counter state. Let’s make it even more complicated. What if we wanted to have defined a starting value that we can change? We could change Counter to accept initialValue prop so that we could use this prop for setting the initial value of the counter and later increment the CounterValue on each click.
This example might be bit more complex than it should be, but it illustrates how requirements impact your structure and data flow. Depending on it, you might have everything as a state, but you also might have multiple levels of depth in a component and require props.
One of newer features in React is something called stateless component. Those are components defined as functions that do not have state. This is newer and a bit more of an advanced topic, so I won’t go into any details about this, but it is important to mention it. Usually we want to have smaller components without lots of logic. Which is the reason why we now have this kind of components.
In this article I wanted to explain how data can be accessed in components. There are still many more parts to React, but before going further it is important to understand components state and props. In the next part of this intro I will be explaining React component lifecycle stages and how a component goes through them.