Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="redux">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
  <script src="https://fb.me/react-15.1.0.js"></script>
  <script src="https://fb.me/react-dom-15.1.0.js"></script>
  <script src="https://npmcdn.com/react-router@2.4.1/umd/ReactRouter.js"></script>
  <script src="https://npmcdn.com/redux@3.5.2/dist/redux.js"></script>
  <script src="https://npmcdn.com/react-redux@4.4.5/dist/react-redux.min.js"></script>
  <script src="https://npmcdn.com/redux-thunk@2.1.0/dist/redux-thunk.js"></script>
</head>
<body>
  <div id="app"></div>
</body>
</html>
 
console.clear();
const { Component } = React;
const { createStore, combineReducers, applyMiddleware } = Redux;
const { connect, Provider } = ReactRedux;
const { Router, Route, hashHistory } = ReactRouter;
/////////////////////////////////////////////////
// ACTION CREATORS
/////////////////////////////////////////////////
const fetchPost = id =>
  (dispatch, getState) => {
    dispatch({
      type: 'FETCH_POST_PENDING',
      payload: { id }
    });
    // fake ajax
    setTimeout(() => {
      dispatch({
        type: 'FETCH_POST_FULFILLED',
        payload: {
          id,
          title: 'Example for ' + id
        }
      })
    }, 1000);
  };
/////////////////////////////////////////////////
// COMPONENTS
/////////////////////////////////////////////////
const mapStateToProps = (state, { params }) => {
  const { postId } = params;
  const post = getPost(state, postId);
  return {
    id: postId,
    post
  };
}
const actionCreators = { fetchPost };
const Post = connect(mapStateToProps, actionCreators)(
  class Post extends Component {
    componentWillMount() {
      this.props.fetchPost(this.props.id);
    }
    componentWillReceiveProps(nextProps) {
      if (nextProps.id !== this.props.id) {
        nextProps.fetchPost(nextProps.id);
      }
    }
    render() {
      const { id, post } = this.props;
      console.log('render', id, post);
      return (
        <div>
          {post ? post.title : 'pending...'}
        </div>
      );
    }
  }
);
/////////////////////////////////////////////////
// REDUCERS
/////////////////////////////////////////////////
const post = (state = null, action) => {
  switch (action.type) {
    case 'FETCH_POST_FULFILLED':
      return action.payload;
    default:
      return state;
  }
};
const postById = (state = {}, action) => {
  switch (action.type) {
    case 'FETCH_POST_FULFILLED':
      return {
        [action.payload.id]: post(state[action.payload.id], action)
      };
    default:
      return state;
  }
};
const reducer = combineReducers({
  postById
});
/////////////////////////////////////////////////
// SELECTORS
/////////////////////////////////////////////////
const getPost = (state, id) =>
  state.postById[id] || null;
/////////////////////////////////////////////////
// STUFF
/////////////////////////////////////////////////
const store = createStore(
  reducer,
  applyMiddleware(ReduxThunk.default)
);
location.hash = '#/posts/1';
setTimeout(function () {
  location.hash = '#/posts/2';
}, 2000);
ReactDOM.render(
  <Provider store={store}>
    <Router history={hashHistory}>
      <Route path="/posts/:postId" component={Post}>
      </Route>
    </Router>
  </Provider>,
  document.getElementById('app')
);
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
anonymouspro
0viewers