What are Props and State?
In short, props are inputs that we pass into components from their parent. State is the internal data that changes and re-renders the component.
Props
On every single React tutorial you will hear passing props
, its almost like React is all about passing props
. Word props
is short for properties
. In very simple terms, they are like attributes that we passed to HTML
elements, like class
. Props
can contain different types of data, such as text, numbers, or functions, and can be passed down to nested components.
<div class="main-section"></div>
Imagine a bucket full of water and a garden. If the bucket represents
props
, and the plants representcomponents
, then watering the plants is likepassing props
ordata
to them. Without water, most plants will die, and without data, most apps won't function.
<Button variant="primary">
Accept
</Button>
<Button variant="secondary">
Decline
</Button>
We have two buttons here, with the variant prop
being used to control their behavior and appearance. By passing primary
and secondary
values to the buttons, we can modify what they do and how they look, which is similar to passing CSS classes.
However, the variant prop
can contain more than just styling - it can also include data and functions.
In summary, props
are similar to CSS classes
, but they are much more powerful and flexible. They allow you to pass data and functionality to components
, making it easier to create highly customizable and reusable code.
State
Imagine visiting a beer company's website. In most countries, the company is required by law to ask for your age, as it is illegal to display alcoholic beverages to minors.
A pop-up window appears, asking you to enter your age or click on a button that says "Yes, I'm over 21 years old," at least in the 🇺🇸.
By clicking on that button, you will change the state
of the component. If you click on "I'm over 21," app's state
will change, and the website will be displayed. If not, you might be kicked out of the website."
Here is an example code if you would like to check it out. It's too long to post in here. Example code
Never mutate React State
React doesn't care what type of data you bind to state - it can handle anything from data
to numbers
and even functions
. Although, if you're using functions, it's best to use useCallback
to avoid any headaches.
It's important to be mindful of mutations
. While you can mutate the state and it may work for your needs, it's not recommended
. React
relies on the fact that you're a cool developer who would never mutate
the state
. Therefore, it won't warn you about it if you do so. However, bugs caused by state mutation can be difficult to track down and fix.
When a component randomly renders or doesn't render, updates or doesn't update, it's like playing lottery. This can lead to confusion and frustration when trying to diagnose a problem. A quick fix by mutating
the state
can cause you endless hours and debugging time. That's why it's best to never mutate the React state
, as it can save you loads of trouble in the long run.
Take a look at this code, and I will explain it line by line below. It isn't the full code because it would have too much boilerplate and my goal here is to explain how stuff works with minimal code.
const [currentColor, setCurrentColor] = React.useState(['#aaaaaa', '#bbbbb', '#ccccc'])
//// map function is used to get colors from currentColor
{currentColor.map((color, index) => {
const colorTable = \`color-\${index}\`;
///
////
<input
id={colorTable}
type="color"
value={currentColor}
onChange={(event) => {
const updatedColors = [...currentColor]
updatedColors[index] = event.target.value
setCurrentColor(updatedColors)
}}
/>
Let's break this code down:
You are probably familiar with this part. We have a useState("")
and it's in array form. In the array, we have 3 colors, with their HEX
values.
We have an input, and it is a browser's build in color picker. User will be able to pick colors. We know that from type="color"
.
value
is set to currentColor
, which is the default state of our useState
hook.
const [currentColor, setCurrentColor] =
React.useState(['#aaaaaa', '#bbbbb', '#ccccc'])
///
<input
id={colorTable}
type="color"
value={currentColor}
/>
{currentColor.map((color, index) => {
const colorTable = \`color-\${index}\`;
onChange={(event) => {
const updatedColors = [...currentColor]
updatedColors[index] = event.target.value
setCurrentColor(updatedColors)
}}
}
Let's examine this part
We have an
onChange
function, which get's invoked when there is anevent
.When there is an event, we create a
new variable/array
calledupdatedColors
.updatedColors
variable is equal to ouruseState()
hook, which is in array form. Since it is an array, we get it's data with...
, the spread operator.[...currentColor]
[index]
comes from the.map
function.updatedColors[index]
set's a color to theevent.target.value
- Finally, we
set the state
withsetCurrentColor
Okay, but why?
I can hear you asking, why are we mapping and creating a new array, and getting the values with the spread operator? What is the point of this?
If we directly mutate
the currentColor
array that comes from the useState
hook, it will cause problems. React relies on the fact that you will never mutate the state directly.
So, we need to create an exact copy of the currentColor
array and modify the copy. Which is updatedColors
, and update our setCurrentColor
with the updatedColors
. With this implementation, React will receive a new object after each render and React will continue to control it's own state and we won't get involved in it's business. React like to perform it's magic under the hood, try not to touch it.
In short summary:
- Modifying the
currentColor
array is bad. - Creating a copy of the
currentColor
array and modifying the copy (updatedColors
) is good.
- Make a new array
- Make your changes on the new array
- Update the state with that modified array
- Leave the original array alone, don't touch it.
Order is important.