Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <script src="//cdnjs.cloudflare.com/ajax/libs/react/15.0.0-rc.1/react-with-addons.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-dom.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/redux/3.3.1/redux.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/react-redux/4.4.0/react-redux.min.js"></script>
  
</head>
<body>
  <div id="app"></div>
</body>
</html>
 
// redux ajax on promise
// noprotect
console.clear();
const {Component, cloneElement} = React;
const {render} = ReactDOM;
const {createStore, applyMiddleware} = Redux;
const {Provider, connect} = ReactRedux;
const promiseMiddleware = ({dispatch, getState}) => next => action => {
  return action && typeof action.then == 'function' ? action.then(dispatch) : next(action);
}
const root = 'http://jsonplaceholder.typicode.com';
const ADD_POST = 'ADD_POST';
const FETCHING = 'FETCHING';
const ERROR = 'ERROR';
function fetchPost(n) {
  return fetch(root + '/posts/' + n)
    .then(res => { if (res.ok) return res.json(); else throw new Error(res.statusText)})
    .then(addPost)
    .catch(handleError);
}
function addPost(post) {
  return {
    type: ADD_POST,
    payload: post
  };
}
function handleError() {
    return {
    type: ERROR
  }
}
function reducer(state, action) {
  switch (action.type) {
    case FETCHING:
      return {...state, fetching: true};
    case ADD_POST:
      return {fetching: false, posts: [...state.posts, action.payload]};
    case 'ERROR':
      return {...state, fetching: false};
    default:
      return state;
  }
}
@connect(state => ({ posts: state.posts, fetching: state.fetching }))
class App extends Component {
  componentDidMount() {
    this.props.dispatch({type: FETCHING});
    this.props.dispatch(fetchPost(this.props.posts.length + 1));
  }
  componentDidUpdate() {
    this.refs.footer.scrollIntoView(false);
  }
  addPost() {
    const {dispatch, posts, fetching} = this.props;
    dispatch({type: FETCHING});
    dispatch(fetchPost(posts.length + 1));
  }
  render() {
    const {dispatch, posts, fetching} = this.props;
    return <div>
      {posts.map(props => cloneElement(<Post />, props))}
      {fetching && <p>fetching...</p>}
      <button onClick={this.addPost.bind(this)}>add post</button>
      <p ref='footer' />
    </div>
  }
}
function Post(props) {
  return <div>
    <h3>{props.title}</h3>
    <p>{props.body}</p>
    <hr />
  </div>
}
const store = createStore(reducer, {posts: []}, applyMiddleware(promiseMiddleware));
render(<Provider store={store}><App /></Provider>, document.querySelector('#app'));
Output

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

Dismiss x
public
Bin info
aves84pro
0viewers