AJAX Request using reqwest [React Redux]

Background:

The website contains a signup form which consists of a Languages dropdown option. In order to get language options from the database, we need to call an AJAX get request.

Problem:

1) Where to trigger the Ajax call in the react life cycle.
2) How to use redux to handle UI changes after AJAX call.
3) How to use reqwest to do it.
P.S: I encountered problems in using isomorphic fetch with Django, because the version I used won’t store the cookie sent back from the Django server (set-cookie header) so I used reqwest instead.

Code:

SignupPage.js:

We apply the thunkMiddleware, the reason will be discussed later

import 'babel-polyfill'
import React from 'react'import ReactDom from 'react-dom'
import {createStore, applyMiddleware} from 'redux'
import thunkMiddleware from 'redux-thunk'
import reducer from './reducers/signup'import SignupApp from './components/SignupApp'
import { Provider } from 'react-redux'
let store = createStore(
  reducer,  applyMiddleware(
    thunkMiddleware
  ));
ReactDom.render(
  <Provider store={store}>
    <SignupApp />
  </Provider>  , document.getElementById('signup-box')
);

SignupApp.js:

nothing special

import React from 'react'
import SignupFormContainer from '../containers/SignupFormContainer'
const SignupApp = () => (
<div style={{height: '100%'}}>
<div className='ui middle aligned center aligned login grid'>
<div className='login column'>
        <SignupFormContainer /></div>
</div>
</div>
)
export default SignupApp

SignupFormContainer.js:

redux-form is used here, if you are not using redux-form, you can replace reduxForm() to connect() from react-redux:

import { reduxForm } from 'redux-form';
import SignupForm from '../components/signupForm'
import { register } from '../actions/signupFormAjaxAction'
const mapDispatchToProps = (dispatch) => {
  return {
    submit: (e, values)=> {
      e.preventDefault();
      dispatch(register(values));
    }
  }
};
// map reducer's state to react component's props
const mapStateToProps = (state) => {
  return {
    // languageReducer
    defaultLanguage: state.fetchLanguage.defaultLanguage,
    languages: state.fetchLanguage.languages,
    // LoginFromReducer
    formInitialized: state.signup.formInitialized,
    showError: state.signup.showError,
    errorMsg: state.signup.errorMsg,
    fieldsStyle: state.signup.fieldsStyle
  }
};
export default reduxForm({
    form: 'SignupForm',// a unique name for this form
    fields: ['first_name', 'last_name', 'username', 'password', 'email', 'display_language'] // all the fields in your form
  },
  mapStateToProps,
  mapDispatchToProps)(SignupForm)

SignupForm.jsx (React Component):

We use the AJAX call in componentDidMount():

class SignupForm extends Component {
  componentDidMount() {
    const {dispatch} = this.props;    dispatch(fetchLanguage())
  }......
}

signupFromAjaxAction.js:

The fetchLanguage() can return a function that allows we can delay and have branchings in dispatch.
Detail: https://www.npmjs.com/package/redux-thunk
Short summary:
– fetchLanuage: Start AJAX request
– requestLanuageOption: Waiting server’s response: maybe trigger UI doing loading     animation
– receiveLanguageOption: Ppdate UI based on the response

export const receiveLanguageOption = (languages, osLanguage) => {
  return {
    type: 'RECEIVE_LANGUAGE_OPTION',
    languages: languages,
    osLanguage: osLanguage,
  };
};
export function fetchLanguage() {

  return function (dispatch) {

    dispatch(requestLanguageOption());
    return reqwest({
      url: '/accounts/languages/',
      type: 'json',
      contentType: 'application/json'
    }).then( // then will be excuted after receving response
      // success and dispatch the language options to the reducer
      json => dispatch(receiveLanguageOption(json.languages, json.os_language)),
      // fail
      (err, msg) => console.log(msg)
    );
  };
};

languageReducer.js:

the reducer will set the state and the state will be passed to all react components. Using object.assign can avoid mutation.

const initialState =
{
  languages: [],
  defaultLanguage: null
};

const languageReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'REQUEST_LANGUAGE_OPTION':
      return state;
    case 'RECEIVE_LANGUAGE_OPTION':
      return Object.assign({}, state, {
        languages: action.languages,
        defaultLanguage: action.osLanguage
      });
    default:
      return state;
  }
};

export default languageReducer;

SignupForm.jsx:

<select className='ui dropdown search' name='display_language' id='display_language' {... display_language}>
  {this.props.languages.map((language, i) => (
<option key={i} value={language[0]}>{language[1]}</option>)}
</select>
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s