As a developer, I've always found React to be a fascinating library for building user interfaces. Its simplicity, flexibility, and efficiency have made it a popular choice in the web development community. Today, I want to delve into two of the most fundamental concepts in React: state and props. Understanding these concepts is crucial for anyone learning React, as they form the backbone of any React application.
In React, state refers to a built-in object that a component can create and manage. This state object is where we store property values that belong to the component. When the state object changes, the component re-renders.
State is similar to props, but it is private and fully controlled by the component. I like to think of state as the "memory" of a component. It allows a component to remember data and render it accordingly.
For example, consider a class Car in React. This class might have a state object that looks like this:
1 class Car extends React.Component { 2 constructor(props) { 3 super(props); 4 this.state = { 5 brand: 'Ford', 6 model: 'Mustang', 7 color: 'red', 8 year: 1964 9 }; 10 } 11 } 12
In React, we initialize state in the constructor method of a class component. However, with the introduction of React Hooks, we can now use state in functional components as well. To update the state, we use the setState() function. This function triggers a re-render of the component, allowing the user interface to reflect the new state.
Here's an example of how we might update the color of the car in the state:
1 this.setState({color: 'blue'}); 2
In the early days of React, class components were the only components that could have a state. These components have several lifecycle methods, which are special methods that automatically get called as a component goes through its lifecycle.
One of these methods is componentDidUpdate(). This method triggers after the state or props of a component update. It's a perfect place to work with the state after a component's state changes.
In React, state updates may be asynchronous. This means that we can't rely on this.state to reflect the new value immediately after calling setState(). Instead, we should use the version of setState() that accepts a function argument. This function will receive the previous state as its argument.
Here's how we might use this form of setState() to update the year of the car in the state:
1 this.setState(prevState => ({ 2 year: prevState.year + 1 3 })); 4
In this example, we're using the previous state to calculate the new state. This ensures that we're working with the most recent state.
In React, props (short for properties) are values passed from a parent component to a child component. They allow components to communicate with each other. Unlike state, props are read-only and cannot be modified by the child component. This immutability helps ensure that data flows unidirectionally from parents to children, making the app's behavior more predictable.
For example, let's say we have a parent component that renders a child component. We can pass data from the parent to the child via props like this:
1 function ParentComponent() { 2 return <ChildComponent color="blue" />; 3 } 4
In the child component, we can access the props using the props object. Each prop is a property on this object. In functional components, we receive the props object as a function argument. In class components, we can access it via this.props.
Here's how we might access the color prop in the ChildComponent:
1 function ChildComponent(props) { 2 return <p>The color is {props.color}.</p>; 3 } 4
As I mentioned earlier, props enable components to communicate with each other. They are especially useful for passing data from parent components to child components. However, they can also be used to pass data between sibling components, with the help of a common parent.
For instance, consider two child components that need to share data. The parent component can manage the shared state and pass it down to the child components via props. When one child component updates the state, the parent re-renders both child components with the new state.
In React, we can validate the props passed to a component using PropTypes. This helps catch bugs by ensuring that the props are of the correct type. If a prop does not match the expected type, React will log a warning in the console in development mode.
Here's an example of how we might validate the color prop in the ChildComponent:
1 import PropTypes from 'prop-types'; 2 3 function ChildComponent(props) { 4 return <p>The color is {props.color}.</p>; 5 } 6 7 ChildComponent.propTypes = { 8 color: PropTypes.string 9 }; 10
In this example, we're specifying that the color prop should be a string. If we pass a non-string value to color, React will log a warning.
Similarities Between State and Props
Both state and props are plain JavaScript objects. They hold information that influences the output of render in React components. Both props and state changes trigger a re-render in React.
While state and props may seem similar, they serve different purposes in a React component.
State is a data structure that starts with a default value when a component mounts and then suffers mutations in time (mostly generated from user events). It's a serializable* representation of one component's internal state. Simply put, state is what allows you to create components that are dynamic and interactive.
1 import React, { useState } from 'react'; 2 3 function Example() { 4 // Declare a new state variable, which we'll call "count" 5 const [count, setCount] = useState(0); 6 7 return ( 8 <div> 9 <p>You clicked {count} times</p> 10 <button onClick={() => setCount(count + 1)}> 11 Click me 12 </button> 13 </div> 14 ); 15 } 16
On the other hand, props (short for “properties”) are variables passed to it by its parent component. Props are how components talk to each other. They are read-only components.
1 function Welcome(props) { 2 return <h1>Hello, {props.name}</h1>; 3 } 4 5 function App() { 6 return <Welcome name="Sara" />; 7 } 8
In the above example, the Welcome component receives props from the App component and uses it to display a message.
While React's built-in state management capabilities are sufficient for small apps, larger apps may require a more robust solution. This is where Redux comes in.
Redux is a predictable state container for JavaScript apps. It helps you manage the state of your app in a predictable way by enforcing certain restrictions on how and when updates can happen. Redux can work with any UI layer, but it's most commonly used with React.
Here's a simple example of how you might use Redux with React:
1 import { createStore } from 'redux'; 2 3 // This is a reducer - a function that takes the current state and an action, and returns a new state 4 function counter(state = 0, action) { 5 switch (action.type) { 6 case 'INCREMENT': 7 return state + 1; 8 case 'DECREMENT': 9 return state - 1; 10 default: 11 return state; 12 } 13 } 14 15 // Create a Redux store to manage the state of your app 16 let store = createStore(counter); 17 18 // You can subscribe to the updates manually, or use bindings to your view layer 19 store.subscribe(() => console.log(store.getState())); 20
Prop drilling is a common pattern in React where props are passed from a parent component down through the component tree to a deeply nested child component. While this works fine for small apps, it can become cumbersome in larger apps.
The Context API is a feature in React that allows you to share values between different components without having to explicitly pass a prop through every level of the tree. It's like a global state for your app.
Here's a simple example of how you might use the Context API to avoid prop drilling:
1 import React, { createContext, useContext, useState } from 'react'; 2 3 // Create a Context object 4 const MyContext = createContext(); 5 6 function ParentComponent() { 7 const [value, setValue] = useState('Hello from context!'); 8 9 // Use the Provider to make a value available to all children 10 return ( 11 <MyContext.Provider value={value}> 12 <ChildComponent /> 13 </MyContext.Provider> 14 ); 15 } 16 17 function ChildComponent() { 18 // Use the useContext Hook to access the value from the context 19 const value = useContext(MyContext); 20 21 return <p>{value}</p>; 22 } 23
In this example, the ChildComponent can access the value from the context without having to receive it as a prop from the ParentComponent.
In this blog post, we've taken a deep dive into the concepts of state and props in React. We've explored what they are, how they work, and how they're used in React components. We've also touched on some advanced concepts like Redux and the Context API.
To recap, state and props are two fundamental concepts in React. State is a component's local data storage, it can change over time and trigger re-renders when it does. Props, on the other hand, are read-only and are used to pass data from parent components to child components.
Understanding these concepts is crucial for anyone working with React. They form the backbone of any React application and are essential for creating dynamic and interactive user interfaces.
I hope you've found this guide helpful. As always, happy coding!
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.