Building a Mini-Instagram with React + Redux

Steven Petryk

@stevenpetryk

What is Redux?

(props) => UI

React gave us the concept of:

import React from 'react'

export default ({
  className,
  children,
  ...rest
}) => (
  <div className={`button ${className}`} {...rest}>
    {children}
  </div>
)

What is Redux?

(state, action) => nextState

And Redux brings us the reducer:

export function photos (state = [], action) {
  switch (action.type) {
    case 'ADD_PHOTO':
      return [
        ...state,
        action.photo
      ]
    default:
      return state
  }
}

Where state is held in a global store.

Actions are dispatched by you.

Actions

{
  type: 'ADD_PHOTO',
  photo: {
    id: 18,
    src: 'http://i.imgur.com/X1kILq9.jpg',
    alt: 'Hey lil guy'
  }
}

An action describes what to do.

(in case you were wondering)

It doesn't specify how.

The Datapath

Store

Action

Reducer 1

Reducer 2

Reducer 3

nextState = 
  r3(r2(r1(state, action), action), action)

uhhh

You know what? Let's just code.

#learnbydoing

Tying into React

Redux only describes the data layer.

We need to take this:

(props) => UI

And turn it into this:

(state, dispatch) => (props) => UI

Tying into React

Think of your average functional React component:

export default const Photo = ({
  photo,
  onLike
}) => (
  <div className='photo' onDoubleClick={onLike}>
    <img src='photo' src={photo.src} />
  </div>
)
  • src is a prop that comes from the state.
  • onLike is a callback that modifies state.

Tying into React

We could wrap this component like so:

import Photo from './Photo'

export default const PhotoContainer = ({
  store,
  photoId
}) => {
  // Mapping state to props
  const photo = store.getState().photos[photoId]

  // Mapping action creators to props
  function onLike () {
    store.dispatch({
      type: 'LIKE_PHOTO',
      payload: {
        photoId
      }
    })
  }  

  return <Photo { ...{photo, onLike} } />
}

Separating concerns reveals what we need.

import Photo from './Photo'

export default const PhotoContainer = ({
  store,
  ...props
}) => (
  <Photo { 
    ...mapStateToProps(store.getState(), props),
    ...mapDispatchToProps(store.dispatch, props)
  } />
)

function mapStateToProps (state, ownProps) {
  return {
    photo: state.photos[ownProps.photoId]
  }
}

function mapDispatchToProps (dispatch, ownProps) {
  return {
    onLike () {
      dispatch({
        type: 'LIKE_PHOTO',
        payload: { photoId: ownProps.photoId }
      })
    }  
  } 
}

Meet React-Redux

(state, dispatch) => props => UI
import { connect } from 'react-redux' // aw hell yeah
import Photo from './Photo'

function mapStateToProps (state, ownProps) {
  return {
    photo: state.photos[ownProps.photoId]
  }
}

function mapDispatchToProps (dispatch, ownProps) {
  return {
    onLike () {
      dispatch({
        type: 'LIKE_PHOTO',
        payload: { photoId: ownProps.photoId }
      })
    }  
  } 
}

export default connect(mapStateToProps, mapDispatchToProps)(Photo)

Time to build something.

Thank you!

Steven Petryk

@stevenpetryk

Full-stack dev at Teeps.org

Building a Mini-Instagram with React+Redux

By Steven Petryk

Building a Mini-Instagram with React+Redux

For the first break in the slides, I fiddled with this: https://runkit.com/stevenpetryk/582a50bcf5baa400148abf44 For the second break in the slides, I coded this: https://github.com/stevenpetryk/react-redux-example

  • 915