My FeedDiscussionsHeadless CMS
New
Sign in
Log inSign up
Learn more about Hashnode Headless CMSHashnode Headless CMS
Collaborate seamlessly with Hashnode Headless CMS for Enterprise.
Upgrade ✨Learn more

Why props are your friend!

Cody Brunner's photo
Cody Brunner
·Feb 26, 2017

Updated 02-March-2017

I certainly never thought this was going to end up on Twitter or Facebook so first off thanks to those who thought this was worth sharing amongst the community. I realize now after reading some of the critical comments that yes this article would be very confusing to someone that is new to React (maybe just confusing in general). That being said I have rewritten the story and added to it somethings I definitely should have but failed too. It was never my intent to confuse anyone; especially someone just starting out with React, as I remember how frustrating React was in the beginning. I just felt the solution I settled on in comparison to other ideas I had was a pretty savvy way to handle the problem.

Disclaimer: This article does assume you have a basic understanding of props & state in React as well as having worked with react-router , react-redux , & redux .


This the first time I've ever done a blog post, I guess this is a blog post? I wanted to share this because I'm pretty impressed with my use of props & ES6. Yes I'm tooting my own horn it happens few and far between trust me.

I'm building my friends photography website using a MERN Stack and the Cloudinary API. The way this works is that when the user comes to the Home page they are greeted with four images that represent their respective collection. So for example you see a bride & groom this is the wedding collection.

When the user selects one of the four images on the Home page an async method, _onClick(), is called. This function is responsible for two things:

  1. Getting the collection of imageUrls from the database that correspond to the collection selected,
  2. and redirecting the user to /portfolio/:collection.

When the user gets to the Portfolio page they are greeted with a Carousel displaying the images. The Porfolio component is connected to the Redux store so it has access to the application state. The piece of state that the Portfolio component cares about is state.carousel . This peice of state is where the data from our api call is housed, so our array of imageUrls. For the remainder of the article it will be referred to as photos as this is the prop name given to it in the Portfolio component:

@connect(
 state => ({
     photos: state.carousel
  })
)

The pickle I ended up running into is how exactly does the Portfolio component know what the user's selection is; because that selection is directly related to what the key will be named in my photos object. Below you an see what photos looks like on a user's selection:

// If user's selection is 'wedding' the key 'wedding' represents the arrary
// of imageUrls. This key could be 'family' if the user selects 'family'.
photos: {
    home: ['img1', 'img2', 'img3', 'img4'],
    message: 'wedding found',
    wedding: ['img1', 'etc']
}

How does the Portfolio component know which collection was chosen by the user?

Below are just a few of my early ideas I had come up with while I watched my Jayhawks clinch their 13th straight Big 12 title.

Answer #1: Use Object.keys().

// From inside componentDidMount():
const array = Object.keys(photos);
    // ['home', 'message', 'wedding']
const collectionName = array[2];
    // 'wedding'

Object.keys() will take in my object photos and return an array of the property names (or keys) as strings. Giving me what I want relatively easily.

Answer #2: Use react-router-redux & substring().

react-router-redux is a package for keeping your router & application state in sync as your user travels to different routes. You must add it's reducer to your Redux Store there by making it an accessible piece of state to connected components. By looking in the redux-devtools in Chrome I can see the following is available to me:

So I could just do the following:

// First give Portfolio access to state.routing.
@connect(
 state => ({
     photos: state.carousel,
     routing: state.routing
  })
)

// Now routing is accessible in the component as this.props 
// and we can deconstruct as needed inside componentDidMount():
    const { params, photos, routing } = this.props;
    const { pathname } = routing.locationBeforeTransition;

// Now I can carryout the substring method to yeild the collection
// chosen by the user.
async componentDidMount() {
    const { params, photos, routing } = this.props;
    const { pathname } = routing.locationBeforeTransition;
    const collection = pathname.substring(11);
    const images = photos[collection];
    await images;
    this.setState({ loading: false });
  }

By using String.prototype.substring() I can get/create substrings of a string by passing 1 argument, the index I want to begin the operation at (the 2nd argument is optional see here for more information). Since I know the string will always start with '/portfolio/' I can just start my substring method at the 11th index and it will return 'wedding' or whatever collection was the param to the route.

Both of these answers get me where I want to be; but this third option is cleaner and uses one of the fundamental ideas behind React: props. By using the props provided by React-Router no operations will need to be carried out on data like with Object.keys() & String.protoype.substring().

Answer #3: Use the props passed down on the Portfolio component by react-router.

By switching over to the react-devtools in Chrome I can look at the component tree of my application on any given route. React-Router's <Router /> component has a state called params who's value is whatever parameter has been passed in the url more info here. This is passed as props down to <RouterContext /> which is then made available as props to all components that are connected to the routing tree.

Routing tree:

<Router>
    <Route path='/' component={App} />
    // Any component listed as a route will have access 
    // to this.props.params
</Router>

Here you can see params is a piece of state on the Router Component:

By accessing the params prop the collection chosen by the user is very neatly provided: params: { collection: "wedding" }.

Don't get confused as params is already a prop made available to the component so their is no need to try and access it as a piece of state from the Redux Store...because it is not a piece of state in the Redux Store.

With the knowledge that this is available to me I can use ES6 to deconstruct params and then use ES6 key interpolation so that now whenever the user chooses a route the correct collection in state will be accessed by the component and ultimately render the correct images to the DOM.

  const { params, photos } = this.props;
  const { collection } = params;
  // Use ES6 key inerpolation so whatever the vaule of 'collection'
  // is will be injected as the key to the photos object.
  const images = photos[collection];

Then I just pass images on to the Carousel component and all is well in the world again.

Moral of the story: Props are your friend!

My project is still a WIP, but I have put a link below as well as a link to the pertinent code of this article in a gist. I've been working with React & Redux since October of 2016 so by all means if I'm wrong feel free to let me know; or if there is a better solution I'm all ears. Happy Coding everyone!

https://github.com/rockchalkwushock/photography-frontend/tree/beta-2

https://gist.github.com/rockchalkwushock/b74cfd6a4c5fa033eb7672282a25dba8