paint-brush
Organizing React Propsby@scott.lively
1,160 reads
1,160 reads

Organizing React Props

by Scott LivelyJune 26th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

As the number of components in the <a href="https://hackernoon.com/tagged/codebase" target="_blank">codebase</a> grows the number of props grows and it becomes important to have a good pattern for passing props from ‘containers’ to ‘dumb components’. I want to walk through how passing props generally starts out and a couple patterns to improve the experience.

Company Mentioned

Mention Thumbnail
featured image - Organizing React Props
Scott Lively HackerNoon profile picture

As the number of components in the codebase grows the number of props grows and it becomes important to have a good pattern for passing props from ‘containers’ to ‘dumb components’. I want to walk through how passing props generally starts out and a couple patterns to improve the experience.

As an example I will be using a todo app with the features listed in this post, but we will split up the app into multiple components. I am also assuming all of the data and handlers are passed as props to the TodosListPage container using redux, recompose, RxJS, etc…

In the beginning we passed props, and it was good

Generally we start out with a container that has all the props and just passes them down to the children. Those children may then pass those props to their children, and so on. One big problem here is if we need to add a new prop to any child of TodosListPage we need to add it to every component until we reach the node that needs the prop. If this is a deeply nested component refactoring props in any way becomes a big pain.

class TodosListPage extends Component {









propTypes = {todos: PropTypes.array.isRequired,newTodoText: PropTypes.string.isRequired,filterText: PropTypes.string.isRequired,fetchTodos: PropTypes.func.isRequired,addTodo: PropTypes.func.isRequired,setNewTodoText: PropTypes.func.isRequired,setFilterText: PropTypes.func.isRequired};








render() {const {todos,newTodoText,addTodo,filterText,setFilterText} = this.props;









return (<div><AddTodoForm newTodoText={newTodoText} addTodo={addTodo}/><TodosFilter filterText={filterText}setFilterText={setFilterText}/><TodoList todos={todos}</div>);}




componentDidMount() {this.props.fetchTodos();}}

Then our props took shape, and it was better

Now instead of just passing every individual prop to the container, we will pass objects that represent the props of the containers children. This means changing props only needs to happen in two places, where we create the object that passes in the props (redux, reselect, RxJS, etc…), and in the receiving component. Any passthrough component is now just that, simply passing props through to the children without any concern for what is in the bag of props. It also has a great side effect of helping you quickly understand which props are only used by the component you are looking at. The warning from PropTypes.shape is also more descriptive of exactly where the prop type warning is coming from. Moving to this pattern was a big win for me.

class TodosListPage extends Component {






propTypes = {fetchTodos: PropTypes.func.isRequired,addTodoForm: PropTypes.shape(AddTodoForm.propTypes).isRequired,todosFilter: PropTypes.shape(TodosFilter.propTypes).isRequired,todosList: PropTypes.shape(TodoList.propTypes).isRequired};


render() {const { addTodoForm, todosList, todosFilter } = this.props;








return (<div><AddTodoForm {...addTodoForm}/><TodosFilter {...todosFilter}/><TodoList {...todosList}/></div>);}




componentDidMount() {this.props.fetchTodos();}}

How I learned stopped worrying and love the container

Lastly, as I’ve started using PropTypes.shape more it becomes clearer that each instance of use probably represents a component that should just be a container. In my experience this can be a little harder to manage. You want to make sure you don’t overdo it, and it requires discipline with how state is stored and processed outside of React. If unsure, I like to err on the side of just having a single container, but in the example above it may be reasonable to connect each component to the store (thus creating a container). I think this approach when done correctly is ideal.

class TodosListPage extends Component {



propTypes = {fetchTodos: PropTypes.func.isRequired};









render() {return (<div><AddTodoForm/><TodosFilter/><TodoList/></div>);}




componentDidMount() {this.props.fetchTodos();}}

Ultimately I would highly recommend moving away from the first approach as soon as possible. It solves a lot of headaches and helps you see the emerging components and patterns in your UI, while also making it easier to refactor.

Hacker Noon is how hackers start their afternoons. We’re a part of the @AMIfamily. We are now accepting submissions and happy to discuss advertising & sponsorship opportunities.

To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon.

If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!