0

I am reading a tutorial on using redux to build a front end login-register-auth app. And I am not quite sure how protectedTest() funciton works in the following code. From what I understand, protectedTest in src/actions/index.js get called, it returns a function that will send a http request to server. However, when we call this.props.protectedTest in src/component/dashboard.js, how come we expect it to communicate with the server(the authoer claim that's what will happen) when it should only create a funciton that will do the job? Or is there something that I am missing here?

src/actions/index.js

import axios from 'axios';  
import { browserHistory } from 'react-router';  
import cookie from 'react-cookie';  
import { AUTH_USER,  
         AUTH_ERROR,
         UNAUTH_USER,
         PROTECTED_TEST } from './types';

const API_URL = 'http://localhost:3000/api';

export function errorHandler(dispatch, error, type) {  
  let errorMessage = '';

  if(error.data.error) {
    errorMessage = error.data.error;
  } else if(error.data{
    errorMessage = error.data;
  } else {
    errorMessage = error;
  }

  if(error.status === 401) {
    dispatch({
      type: type,
      payload: 'You are not authorized to do this. Please login and try again.'
    });
    logoutUser();
  } else {
    dispatch({
      type: type,
      payload: errorMessage
    });
  }
}

export function loginUser({ email, password }) {  
  return function(dispatch) {
    axios.post(`${API_URL}/auth/login`, { email, password })
    .then(response => {
      cookie.save('token', response.data.token, { path: '/' });
      dispatch({ type: AUTH_USER });
      window.location.href = CLIENT_ROOT_URL + '/dashboard';
    })
    .catch((error) => {
      errorHandler(dispatch, error.response, AUTH_ERROR)
    });
    }
  }

export function registerUser({ email, firstName, lastName, password }) {  
  return function(dispatch) {
    axios.post(`${API_URL}/auth/register`, { email, firstName, lastName, password })
    .then(response => {
      cookie.save('token', response.data.token, { path: '/' });
      dispatch({ type: AUTH_USER });
      window.location.href = CLIENT_ROOT_URL + '/dashboard';
    })
    .catch((error) => {
      errorHandler(dispatch, error.response, AUTH_ERROR)
    });
  }
}

export function logoutUser() {  
  return function (dispatch) {
    dispatch({ type: UNAUTH_USER });
    cookie.remove('token', { path: '/' });

    window.location.href = CLIENT_ROOT_URL + '/login';
  }
}

export function protectedTest() {  
  return function(dispatch) {
    axios.get(`${API_URL}/protected`, {
      headers: { 'Authorization': cookie.load('token') }
    })
    .then(response => {
      dispatch({
        type: PROTECTED_TEST,
        payload: response.data.content
      });
    })
    .catch((error) => {
      errorHandler(dispatch, error.response, AUTH_ERROR)
    });
  }
}

src/components/dashboard.js

import React, { Component } from 'react';  
import { connect } from 'react-redux';  
import * as actions from '../actions';

class Dashboard extends Component {

  constructor(props) {
    super(props);

    this.props.protectedTest();
  }

  renderContent() {
    if(this.props.content) {
      return (
        <p>{this.props.content}</p>
      );
    }
  }

  render() {
    return (
      <div>
        {this.renderContent()}
      </div>
    );
  }
}

function mapStateToProps(state) {  
  return { content: state.auth.content };
}

export default connect(mapStateToProps, actions)(Dashboard);  
2
  • If the API_URL points to your local host then you should build the server, since it is running on you local machine. Also what does it have to do with python? Commented Nov 24, 2017 at 7:39
  • @cowCrazy sorry I used a wrong tag and title Commented Nov 24, 2017 at 9:00

1 Answer 1

1

how come we expect it to communicate with the server(the authoer claim that's what will happen) when it should only create a funciton that will do the job

Original redux library operates with simple javascript objects, yes. That means no async actions, since an application needs to know what action to execute immediately.

But, obviously, apps usually need to do some async operations, that's where redux-thunk comes in.

And it is used in the tutorial also, check the "Create index.js and enter the following:" section

// ...

import reduxThunk from 'redux-thunk';

// ...

const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);  
const store = createStoreWithMiddleware(reducers);

// ...

Redux thunk would invoke immediately any action function with a dispatch function where you would do some necessary async operations.

https://github.com/gaearon/redux-thunk/blob/master/src/index.js#L3

And after you received some results you would just dispatch a plain old action with received data.

dispatch({
    type: PROTECTED_TEST,
    payload: response.data.content
});

Here's a video I've found about redux-thunk: https://www.youtube.com/watch?v=1QI-UE3-0PU

Also the redux-thunk repository is well described in its readme file.

Sign up to request clarification or add additional context in comments.

2 Comments

thanks for the answer. I understand when using redux thunk, actions can be functions, and when we dispatch(action) given action is a function, action(dispatch) will be called since redux thunk check the action type, and passes dispatch to action if action is a function. However, I don't quite understand why calling this.props.protectedTest() in this scenario invoked the above mention behavior. I would expect it to behave like this if it's dispatch(protectedTest()), because then we will be dispatching a returned function from protectedTest. But now no dispatch was called?
@I-PINGOu protectedTest is an async action creator, it was binded somewhere inside the connect(mapStateToProps, actions) call (github.com/reactjs/react-redux/blob/master/src/connect/… exactly). The actions can be a function, an object, or can be skipped. That way you can use protectedTest without passing a dispatch object explicitly. And as for coding style, since redux thunk expanded dispatch functionality to handle functions, yes, you can use dispatch(protectedTest()) inside your components, but it's better to keep use of action creators consistent.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.