1

I am learning how to use Redux. I would like to create a simple application with only one button. When the button is clicked I want to do a rest api call and when the response comes back the response content needs to be displayed.

What I would like to do is send a store.dispatch(CardAction.GET_CARDS) message to Redux when user clicks on the button. I do not want to call rest api directly from the button's onClick handler.

When the answer is received I intend to to the same: send an event with store.dispatch(CardAction.UPDATE_UI) and somehow at the background I want to update the Redux's status.

I hope that this concept is align with React + Redux.

I have some JavaScript code done but some part of it are missing. Could you please help me to put parts together?

index.jsp

<!DOCTYPE html>
<%@page session="false"%>
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>

<html>
    <head>
        <meta http-equiv="CONTENT-TYPE" content="text/html; charset=UTF-8">
        <base href="${pageContext.request.contextPath}/" />
        <link rel="icon" type="image/x-icon" href="public/image/favicon.ico">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap-theme.min.css">
    </head>
    <body>
        <div id="root"></div>
        <script type="text/javascript" src="bundle.js"></script>
    </body>
</html>

App.js

let store = createStore(reducers);

ReactDom.render(
    <Provider store={store}>
        <Card/>
    </Provider>,
    document.getElementById('root')
);

Card.js

export default class Card extends React.Component {
    render() {
        return (
            <div>
                ...
                <Button onClick={() => store.dispatch(CardAction.GET_CARDS)}>rest call</Button>
            </div>
        )
    }
}

ActionType.js

export const GET_CARDS = 'get-cards';
export const UPDATE_UI = 'update-ui';

CardAction.js

export function getCards(param1, param2) {
    return createAction(ActionType.GET_CARDS, (param1, param2) => ({ value1, value2 }))
}

export function updateUi() {
    return createAction(ActionType.UPDATE_UI)
}

RootReducer.js

export const reducers = (state = {}, action) => {
    return action
};

RestClient.js

export default {
    cardPost(param1, param2) {
        const url = ...;

        fetch(url, {
            method: 'POST',
            credentials: 'include'
        })
            .then(response => {
                if (response.ok) {
                    console.info('rest response have arrived');
                    store.dispatch(CardAction.UPDATE_UI)
                } else {
                    console.info('error appeared during calling rest api');
                    //store.dispatch(CardAction.SHOW_ERROR)
                }
            })
            .catch(function(err) {
                console.info(err + ' Url: ' + url)
            })
    }
}
2
  • Is "createAction" a custom function of yours? Commented Dec 1, 2016 at 10:49
  • it comes from import { createAction } from 'redux-actions' Commented Dec 1, 2016 at 11:06

1 Answer 1

2

You should never call store.dispatch() from a component. Instead, you should import a previously built action and let the Redux flow do the remaining stuff. The reducer shouldn't return an action, instead, it should return a new state, without mutating the previous one. I'd suggest you should first compensate some of the comprehensible lack of experience with Redux, and then you can try to follow along with a React-Redux-Rest tutorial like this one: https://medium.com/@rajaraodv/a-guide-for-building-a-react-redux-crud-app-7fe0b8943d0f#.cnat3gbcx

[EDIT] Here's what I'd do

// component Card.js
import {getCards} from "CardAction";

export default class Card extends React.Component {
    render() {
        return (
            <div>
                ...
                <Button onClick={getCards(param1, param2)}>rest call</Button>
            </div>
        )
    }
}

// action CardAction.js
const receivedCards = (cards) => ({
	type: "RECEIVED_CARDS",
	cards
})

export function getCards(param1, param2) {
    // idk where you're gonna use these params btw
    // also please note that fetch() isn't supported by older browsers. Here I'm showing you a simple example with axios, which basically performs the same operation. Feel free to adapt this example code as you want.
	return function(dispatch) {
		return axios({
			url: server + "endpoint",
			timeout: 20000,
			method: 'get'
		})
		.then(function(response) {
			let cards = response.data;
			dispatch(receivedCards(cards));
		})
		.catch(function(response){
			console.log(response.data.error);
		})
	}
};

// reducer reducer.js
const initialState = {};
export default (state = initialState, action) => {
  switch(action.type) {
    case "RECEIVED_CARDS":
      return Object.assign({},
        state,
        {cards: action.cards});
    default:
      return state;
  }
}

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

3 Comments

That means I need to do something like this? <Button onClick={() => CardAction.getCards(param1, param2)}>rest call</Button> In that case where I can put the store.dispatch() code?
Thank you for your help. Your code works properly except the rest callback part. I get this error: TypeError: dispatch is not a function. If i use this.props.dispatch(...) instead of dispatch(...) then the error is TypeError: this is undefined. If .then((response) => {this.props.dispatch(...)} is used then the error is TypeError: _this is null. Could you please help me?
I also tried that without any success. My component's click handler: onClick={doLogin(this.props.dispatch, 'param1', 'papam2') - export default connect()(Card) - and the action class: getCards(dispatch, param1, param2) -> dispatch(receivedCards(cards)) The error what I get is "TypeError: dispatch is not a function"

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.