Skip to content

Instantly share code, notes, and snippets.

@odewahn
Last active June 7, 2017 14:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save odewahn/2f7db38645090973eb46c1262c26ca58 to your computer and use it in GitHub Desktop.
Save odewahn/2f7db38645090973eb46c1262c26ca58 to your computer and use it in GitHub Desktop.
This is a better syntax for creating connected component

If you're using Redux and connect, this is a nice syntax for creating connected components:

export default connect((state) => state)(React.createClass({
  render: function() {
    ...
    this.props.Projects.get("ProjectName") // access the state tree provided by combineReducers
  }
})

You can then access this component somewhere else like this:

import SomeComponent from './components/some-connected-component'

...

  <SomeComponent />

This way, SomeComponent will have access to the entire state tree (which may not be what you want, in which case you should pass the state tree down in some other way.

Also, just for fun, here's a snippet of how to set up the relevant other middleware:

import React from 'react';
import ReactDOM from 'react-dom'

// Import react-router
import { Router, Route, IndexRoute, hashHistory} from 'react-router'

// Import redux stuff
import {createStore, applyMiddleware} from 'redux'
import {Provider, connect} from 'react-redux'
import thunk from 'redux-thunk'
import stateTree from './state/index'


// create a store that has redux-thunk middleware enabled
// * https://github.com/gaearon/redux-thunk
// * https://github.com/rackt/redux/issues/291

const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const store = createStoreWithMiddleware(stateTree);

ReactDOM.render(
  <Provider store={store}>
     <Router history={hashHistory}>{routes}</Router>
   </Provider>,
   document.getElementById('app')
)

Note that stateTree is an index file that pulls all of the various state elements into a single reducer using combineReducer, like this:

/*********************************************************************
||  Import required modules
*********************************************************************/
import { combineReducers } from 'redux'
import {fromJS} from 'immutable'

import Config from './config'
import Notification from './notification'
import User from './user'
import Docker from './docker'
import Nav from './nav'
import Projects from './projects'
import Search from './search'
import Git from './git'
import ProjectTemplate from './project-template'


/*
The combineReducer function put all the reducers into a plain
old javascript object, so when you go to access it, you use regular
JS notation, not immutable.  The nodes, though, are still all immutable. See
this discussion on stackoverflow for a better explanation:

  -  http://stackoverflow.com/questions/32674767/redux-reducers-initializing-same-state-key
*/
export default combineReducers({
  Config,
  Notification,
  User,
  Docker,
  Nav,
  Projects,
  Search,
  Git,
  ProjectTemplate
})

Finally, here's a sample reducer. I like to keep everything for the reducer in one file:

/*********************************************************************
||  Import required modules
*********************************************************************/
import { fromJS, Map } from "immutable";
import { standaloneErrorNotification } from "./notification";
import { validateAPIKey } from "./user";
import "whatwg-fetch";
import { fetchJSONFromAPI, fetchTextFromAPI } from "./common";

/*********************************************************************
||  Define the state tree
||  NOTE: This is still JS, so just use this for things that
||  can be seen on the client!
*********************************************************************/
export const INITIAL_STATE = fromJS({
  Config: {
    APIKey: "",
    LaunchbotHost: "",
    HostIp: "",
    DockerCommandPath: "",
    ProjectDirectory: "",
    DockerHost: "",
    CACert: "",
    Key: "",
    Cert: "",
    Username: "",
    Email: ""
  }
});

/*********************************************************************
||  The reducer
*********************************************************************/
export default function(state = INITIAL_STATE, action) {
  switch (action.type) {
    case "setConfig":
      return state.merge(action.config);
    case "setConfigField":
      return state.setIn(["Config", action.key], action.value);
  }
  return state;
}

/*********************************************************************
||  Actions
*********************************************************************/

export function setConfig(json) {
  return { type: "setConfig", config: fromJS(json) };
}

// Sets a field value
export function setConfigField(key, value) {
  return {
    type: "setConfigField",
    key: key,
    value: value
  };
}

/*********************************************************************
||  Async Actions
*********************************************************************/

export function fetchConfigInfo() {
  return (dispatch, getState) => {
    return fetch("/api/config", { method: "GET", credentials: "include" })
      .then(response => response.json())
      .then(json => {
        dispatch(setConfig(json));
        dispatch(validateAPIKey());
      });
  };
}

export function saveConfig() {
  return (dispatch, getState) => {
    dispatch(
      fetchJSONFromAPI(
        "/api/config",
        {
          Config: JSON.stringify(getState().Config.get("Config").toJS())
        },
        json => {
          dispatch(validateAPIKey());
        }
      )
    );
  };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment