0

This question is the third part to this question. Episode 1 was resolved, episode 2 was also resolved and now I present episode 3.

React newbie here, but proficient in Django.I have a simple fetch function which worked perfectly but then my project had no login authentication involved. Now that I have configured login JWT authentication to it, I am not able load the data. The backend part is designed in Django DRF, and is simply returning me a bunch of objects. My frontend is making a request to the backend along with a AccessToken, but I get this error:

Unhandled Rejection (Error): Actions must be plain objects. Use custom middleware for async actions.

My project has react-redux and redux-thunk and it probably has something to do with these. I am new to redux too :\

This is my file:

import React, {Component} from 'react';
import {Card, CardBody, CardHeader, Col, Row, Table} from 'reactstrap';
import {getAccessToken} from '../helpers/api'
import {reactLocalStorage} from "reactjs-localstorage";
import {API_TOKENS} from "../data/storage";
import {errorGettingUserInfoNotification, signINAgainNotification} from "../helpers/notifications";




class all_orders extends Component {
    state = {
        todos: []
    };


    async componentDidMount() {
        try {
            const res = await fetch('http://127.0.0.1:8000/api/allorders/',

                {
                    headers: {
                        // your headers there as pair key-value, matching what your API is expecting, for example:
                        'details': getAccessToken()
                    }
                });
            // fetching the data from api, before the page loaded
            const todos = await res.json();
            console.log(todos);
            this.setState({
                todos
            });
        } catch (e) {
            console.log(e);
        }
    }


    render() {

        // const userList = usersData.filter((user) => user.id < 10)

        return (
            <div className="animated fadeIn">
                <Row>
                    <Col xl={12}>
                        <Card>
                            <CardHeader>
                                <i className="fa fa-align-justify"></i> All Orders <small
                                className="text-muted"></small>
                            </CardHeader>
                            <CardBody>
                                <ul className="nav nav-tabs">
                                    <li className="nav-item">
                                        <a className="nav-link active"
                                           href="base/all-orders#/base/hold-orders">Active</a>
                                    </li>
                                    <li className="nav-item">
                                        <a className="nav-item" href="base/all-orders#/base/hold-orders">Link</a>
                                    </li>
                                    <li className="nav-item">
                                        <a className="nav-item" href="base/all-orders#/base/hold-orders">Link</a>
                                    </li>
                                    <li className="nav-item">
                                        <a className="nav-link disabled"
                                           href="base/all-orders#/base/hold-orders">Disabled</a>
                                    </li>
                                </ul>
                                <Table responsive hover>
                                    <thead>
                                    <tr>
                                        <th scope="col">Name</th>
                                        <th scope="col">SKU ID</th>
                                        <th scope="col">Quantity</th>
                                        <th scope="col">Dimensions</th>
                                        <th scope="col">Weight</th>
                                        <th scope="col">Volume</th>
                                        <th scope="col">Origin</th>
                                        <th scope="col">Destination</th>
                                        <th scope="col">Date</th>
                                    </tr>
                                    </thead>
                                    <tbody>


                                    {this.state.todos.map(item => (
                                        <tr>
                                            <td>{item.name}</td>
                                            <td>{item.pid}</td>
                                            <td>{item.quantity}</td>
                                            <td>{item.length} X {item.width} X {item.height}</td>
                                            <td>{item.weight}</td>
                                            <td>{item.volume}</td>
                                            <td>{item.origin}</td>
                                            <td>{item.destination}</td>
                                            <td>{item.time}</td>
                                        </tr>
                                    ))}


                                    </tbody>
                                </Table>
                            </CardBody>
                        </Card>
                    </Col>
                </Row>
            </div>
        )
    }
}

export default all_orders;

This is my api.js file which handles all the redux actions:

/*
    Contains all URLs and ApiFunctions
 */
import axios from "axios";
import {reactLocalStorage} from "reactjs-localstorage";

import {API_TOKENS} from "../data/storage";
import {errorGettingUserInfoNotification, signINAgainNotification} from "./notifications";


const BASE_URL = "http://127.0.0.1:8000";
axios.defaults.baseURL = BASE_URL;
axios.defaults.headers.get['Content-Type'] = 'application/x-www-urlencoded';


const GET_TOKEN_PAIR = '/sign-in/';
const CREATE_ACCOUNT = '/sign-up/';
const USERNAME_AVAILABLE = '/username/available/';
const REFRESH_ACCESS_TOKEN = '/refresh/';
const USER_DETAILS = "/user/meta/";


export const getAccessToken = () => {
    return new Promise(async (resolve, reject) => {
        const data = reactLocalStorage.getObject(API_TOKENS);

        if (!data)
            return resolve('No User found');

        let access_token = '';
        const expires = new Date(data.expires * 1000);
        const currentTime = new Date();

        if (expires > currentTime) {
            access_token = data.tokens.access;
        } else {
            try {
                const new_token = await loadOpenUrl(REFRESH_ACCESS_TOKEN, {
                    method: 'post',
                    data: {
                        refresh: data.tokens.refresh,
                    }
                });
                access_token = new_token.access;
                const expires = new_token.expires;

                reactLocalStorage.setObject(API_TOKENS, {
                    tokens: {
                        ...data.tokens,
                        access: access_token
                    },
                    expires: expires
                });

            } catch (e) {
                try {
                    if (e.data.code === "token_not_valid")
                        signINAgainNotification();
                    else
                        errorGettingUserInfoNotification();
                } catch (e) {
                    // pass
                }

                return reject('Error refreshing token', e);
            }
        }

        return resolve(access_token);
    });
};

export const loadOpenUrl = async (url, config = {}) => {
    return new Promise((resolve, reject) => {
        axios(url, config)
            .then((res) => resolve(res.data))
            .catch(err => reject(err.response))
    });
};

export const loadSecureUrl = (url, config) => {
    return new Promise(async (resolve, reject) => {
        try {
            const data = await loadOpenUrl(url, {
                ...config,
                headers: {
                    'Authorization': `Bearer ${await getAccessToken()}`
                }
            });
            return resolve(data)
        } catch (e) {
            return reject(e)
        }
    })
};

export const getAPITokens = async (username, password) => {
    return loadOpenUrl(GET_TOKEN_PAIR, {
        data: {
            username: username,
            password: password
        },
        method: "post"
    })
};

export const getUserDetails = () => {

    //TODO: Show loading screen
    const data = loadSecureUrl(USER_DETAILS);

    //TODO: hide loading screen
    return data;
};


export const isUsernameAvailable = async (username) => {
    try {
        return await loadOpenUrl(USERNAME_AVAILABLE, {
            params: {
                username: username
            }
        })
    } catch (e) {
        console.log(e);
        return false
    }

};

export const signUpUser = async (data) => {
    return loadOpenUrl(CREATE_ACCOUNT, {
        method: 'post',
        data: data
    })
};
Rohit Kumar
  • 684
  • 2
  • 17
  • 39

1 Answers1

0

You have got and issue with Redux somewhere else in your app, not in the code you have shared.

Looks like there is an action creator function that returns something different than a plain object (which is basically an action).

You should return only objects from action creators. More about action creators on Redux official site.

  • I have updated my `api.js` file which handles all of the redux actions. Can you please guide me where to make the changes ? – Rohit Kumar Aug 08 '19 at 12:47
  • None of these functions are actually Redux action creators. Try to wrap them into redux-thunk middleware (so you can `dispatch()` to Redux the data you get from HTTP requests). – Anton Bahurinsky Aug 08 '19 at 13:00