0

I'm creating a budget app in React.js, where my parent component has an Overall Balance, and one can create any number of specific "Budget" components (say, Vacations) , from which one can create any number of "Entry" components (say, I'll spend x number of dollars in San Francisco). My initial thought was that the parent can have an array of "Budget" components in its state that can keep growing and changing, and the Budget component can have an array of "Entry" components in its state and that can keep growing as well. However, I realize that this is bad practice because only one component should have state.

What is the best way to manage both my Budgets and their entries in the parent component, given that anyone should be able to go back and change the number of entries in any previously created budget?

Thanks for your help, and I'm sorry if this is confusing!

1
  • "only one component should have state" is not true at all. It is perfectly fine and normal for any component to have state. Even presentational components can have their own state. What you've proposed isn't bad practice at all IMO. Commented Jul 6, 2017 at 14:36

1 Answer 1

1

Yep, I think you're on the right track with the "only one component should have the state" idea. The commenter on your question is right that state can be put anywhere in the component tree in React - and that's often what you do with state related to the UI (e.g. is this button selected or not). But when it comes to application state, i.e. the data that your app is rendering, it's usually convenient to put it all in one place.

Just think about the pure data structure at first, don't worry about React.

It's probably going to end up looking like an array of budget objects, and inside each of those budget objects there's an array of entries:

[
  {
    title: 'Vacations',
    entries: [
      {
        spent: 10,
        place: 'San Francisco',
        ...
      },
      ...
    ],
  },
  ...
]

Then when it comes to React you'll want to put that state in a main <App /> component. The responsibility of <App /> will be to render a list of <Budget /> components. Each one of those budget components will get it's data and entries passed into it as props. So something like,

class App extends Component {
  constructor () {
    this.state = {
      budgets: [... as above ...]
    }
  }

  render () {
    const { budgets } = this.state
    return (
      <div>
        {this.state.budgets.map(budget => {
          <Budget key={budget.title} {...budget} />
        })}
      </div>
    )
  }
}

Inside <Budget /> you can render the array of <Entry /> components in a similar way since each <Budget /> will receive an entries array as a prop.

In terms of changing data, as long as you pass down handlers from <App /> into the child components, and those handlers call setState() inside <App /> to make changes to the budgets data then your app will react to those changes and re-render from top to bottom.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your response, this makes a lot of sense. How would I make it so these budgets would only appear on click of some button?
You could just add a flag to your state in <App />, something like showBudgets: false, and then conditionally render the budgets list like {showBudgets && <div>...</div>}. Then add a button with an onClick that does setState({ showBudgets: true }).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.