DEV Community

Explain State and Props Like I'm Five

Gift Egwuenu on October 31, 2018

I need to fully grasp the idea behind State and Props. Anyone willing to help demystify these terms in the simplest way.

Collapse
 
_phzn profile image
Kevin Lewis

I'd really welcome feedback if this isn't right or the best way of explaining them, but here's a shot:

State holds data and variables which are specific to a component. They work like object/class properties.

Props are options which you can pass into a component when you create them, often as an attribute, such as <Person eyes="brown"> - the prop is eyes, value is brown. You have to handle that in your component.

Collapse
 
lauragift21 profile image
Gift Egwuenu

Thanks for breaking this down

Collapse
 
david_j_eddy profile image
David J Eddy

What is the difference between 'state' and an OOP object?

Collapse
 
zspencer profile image
Zee • Edited

Hey David,

In my understanding, React and Vue state is an extension of an object, with some tools for noticing changes and informing the React or Vue framework about those changes so the framework/virtual machine can do something with those changes.

So state in react is a kind of object, but the inverse is not true (object is not a kind of state)

I hope this helps!

Zee

Thread Thread
 
david_j_eddy profile image
David J Eddy

Very helpful, TY. Coming from a backend programming perspective and just recently learning VueJS state confused me a bit. Your explanation helps.

Collapse
 
zspencer profile image
Zee

Hey there!

Props and states are driven from the philosophy that "When I make a change to a piece of code, I want that to not require changes to other pieces of code, so that I can make changes swiftly and fearlessly!"

The secret to fearless changes in software is knowing that A) you can set boundaries B) those boundaries will be respected and C) You can change those boundaries as you learn. Props and State are two useful boundaries that are provided by reactive frameworks like React and Vue.

When I think about the defining boundaries with props and state, I think about who "owns" the information.

Props are for holding bits of information or functions that other components own. The information inside of them may not be changed. "Look, but don't touch!" Think of it like letting your friend or sibling look at a picture on your phone. You wouldn't want them opening up your messages app or swiping through the photos. Whereas State is for information that the component itself owns. The information may be changed willy nilly by the component.

The next question becomes "what does ownership mean?" which, I think, is where the difficulty in delineating between props and state arises.

Let's pretend you're building a bank app. You want to add a feature that allows Person A to transfer money to Person B, so you wind up with some components:

  • TransferWidget which holds the state about what accounts to transfer between and the amount
  • AccountSelector which is responsible for allowing the user to select an account
  • AccountDollarInput, which allows the user to input a number and validates the account balance will support it
class TransferWidget extends React.Component {
  render() {
    return (<div>Hey there! Move <AccountDollarInput account={this.state.fromAccount} /> from 
    <AccountSelector selected={this.state.fromAccount} /> to 
    <AccountSelector selected={this.state.toAccount}  />)
}

In this example, the TransferWidget owns knowing about:

  • Which account money is coming from
  • Which account money is going into
  • How much money is being transferred.

The sub-components, AccountSelector and AccountDollarInput are given read-access to the state that they need from the TransferWidget as props so that they can use that information to make decisions. However, these sub-components cannot change that information! Agh foiled by props!

But are we?! Properties not only can provide data to a sub-component, but can also provide functions that have access to the TransferWidgets state! (see onSelected and onInput below)

class TransferWidget  extends React.Component {
  render() {
    return (<div>Hey there! Move <AccountDollarInput account={this.state.fromAccount} onInput={(amount) => this.setState({ amount })} /> from 
    <AccountSelector selected={this.state.fromAccount} onSelected={(fromAccount) => this.setState({ fromAccount })} /> to 
    <AccountSelector selected={this.state.toAccount} onSelected={(toAccount) => this.setState({ toAccount })} />)
}

These functions, when called by the AccountSelector or AccountDollarInput sub-components are used to provide information to their parent component's (TransferWidget in this case) state, which are then passed back down into the children components as properties.

But WHY?! This is complicated, passing both data and a function into a component to change that data seems like it's taking quite a few steps when one could suffice. The pragmatic answer is that the TransferWidget needs to know about the data that is selected within the AccountSelector and AccountDollarInput sub-components; without knowing about what is going on inside of the AccountSelector widget. All it knows is the agreement that underlies these components: "I give you the currently selected account, and if that changes, you tell me what the new one is."

But seriously Zee, WHY?! The more-theoretical answer comes from a few different programming concepts that take this well beyond the "ELI5" stage, but I know you can handle it:

  • Separation of Concerns - (paraphrased) "My business is my business, your business is your business. You only get to do the things I allow you to with my business, and I only can do things that you allow me to with your business."
  • Command Query Separation - (paraphrased) "A function that changes data must not also return data, and vice versa"
  • Single Responsibility Principle - (paraphrased) "Every component/function/module has one job"

I hope this helps, even though we steered out of the ELI5 side of things!

Zee

Collapse
 
vonheikemen profile image
Heiker • Edited

Maybe not quite accurate, but here I go:

Think in a sandwich. You can imaging two types of ingredients, there are the ones that you put in like tomato, bacon or cheese. This come from the outside world. But the bread itself is also made of some ingredients, those are already baked in. You could make a sandwich component like this:

<my-sandwich vegetable="tomato" />

See. In here you pass a vegetable of your choice to the sandwich component. You can think of state as values that live inside the component. And props as values that come from the outside.

I also like to think of components as functions (in some libraries that is actually the case), and in that sense the "props" are just the arguments that you give to the component and state are the variables that you declare inside the component.

Collapse
 
thobyv profile image
Thoby V ijishakin • Edited

Hi Gift. I'm glad to be able to help out.

State is Just Data. You know.. The usual data we see, share, use everyday.

In programming, we just kick around 2 things all our lives:

Data & Algorithms (you know..to manipulate data)

So just in case you're building a web based application. State is basically the data associated, down from usernames and JWT's to button-hover css classes.

Props is just more dynamic data ...this is more simpler than state to grasp, imagine you need to pass data(state) around from one house (function) to another to make use of it.

State isn't just associated with web components.

Games => Scores, health, Level, Position on screen of player etc.

Programming Languages => Function names, Object instances etc.

Human behavior => Emotions, Age, Portfolio etc.

Anything that holds information that can be changed/or not as well.

Collapse
 
luispa profile image
LuisPa

Imagin state as a JavaScript object.

State comes from inside the parent or inside the children, and can be traspased to another children as a prop. You can only change the state inside the creator of the state.

Props comes from the parent to the children. The children can’t change the prop (it’s read only).

Collapse
 
krofdrakula profile image
Klemen Slavič

Props are a bunch of things someone else gives you. Someone else is responsible for storing them and handling changes to them (like giving you a function to call when you want something to change).

State is a bunch of things you store yourself that noone gives you and can pass along to others. You are responsible for storing it and deciding what to do when someone wants to change it. You can pass functions that can be called by other components to tell you when they want something to change.

It's up to you to decide if a given piece of data should live outside of your component, or inside the state of some component.

Generally, it's best to avoid all state in a component as it's not accessible to the outside world, and you definitely do not want to store values that are supposed to be coming from props in the state. That will hurt you later, since you would have to guarantee that your internal state always stays in sync with the props coming in.

I know this may be a bit premature, so feel free to skip the rest of this comment, but it will make so much sense later when you're comfortable with the concepts.


There are techniques to avoid having state within your component, like using a state library (tiny ones like Unistore, Reduxless, etc.) or just a simple component you can build using withState:

import { Component } from 'react';

const withState = (render, initialState = {}) => {
  return class extends Component {
    state = initialState;
    render() {
      return render({
        ...this.props,
        ...this.state,
        setState: (...args) => this.setState(...args)

      });
    }
  };
};

export default withState;

This is how you use it:

import withState from './with_state'; // the file above

// this component just calls setState and shows the count
const CountButton = ({ count, setState }) => {
  const onButtonClicked= () => setState({ count: count + 1});
  return (
    <button onClick={onButtonClicked}>
      I was pressed {count} times.
    </button>
  );
};

// this component is created with the starting state {count:0}
const CountButtonWithState = withState(CountButton, { count: 0 });

export default CountButtonWithState;

When used in your app:

import CountButton from './count_button'; // the above file

const App = () => <CountButton/>

I also advocate an approach where all of the logic about converting data, formatting it, etc. is moved outside of the component, leaving just a small template behind. You can read about it in my other post: