1

I've written React app that is inner state based. It uses "axios" library for fetching data from Web API. It looks as following:

class OrdersTable extends React.Component {
  constructor() {
    super();

    this.state = {
      orders: [],
      ...
  }

  componentDidMount() {
    setTimeout(() => {
      axios.get("http://localhost:1234/api/orders").then(response => {
        this.setState({
          orders: response.data,
        });
      });
    }, 2000);
  }

  render () {
    return (
      <div className="content-wrapper">
        <div className="content-left">
           <BootstrapTable keyField='id' data={this.state.orders} columns={this.state.columns}
             rowStyle = {this.state.rowStyle} rowEvents={this.rowEvents}
             caption={<CaptionOrders title="Orders" />} noDataIndication={<NoData />} {...this.props} />
           <Legend />
        </div>
      </div>
    )
  }
}

I'd like to transform it to use Redux instead of inner state. I've started with the following:

index.js:

const store = createStore(reducer);

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

Actions:

import { LOAD_DATA } from '../constants/action-types';

export const loadData = orders => ({
  type: LOAD_DATA,
  payload: orders
})

Reducer:

export default initialState = {
  orders: []
};

const reducer = (state = initialState, action) => {
  switch(action.type) {
    case LOAD_DATA:
      return {
        ...state, orders: action.payload };
    default:
      return state;
  }
}

Container:

const mapStateToProps = (state) => ({
  orders: state.orders
})

const mapDispatchToProps = (dispatch) => ({
  // Should "axios" call be here and if so, how should look like?
});

export default connect(mapStateToProps, mapDispatchToProps)(OrdersTable);

Presentational component:

How can I use the orders state from Redux in OrdersTable component?
Tholle
  • 108,070
  • 19
  • 198
  • 189
tesicg
  • 3,971
  • 16
  • 62
  • 121
  • 1
    You can use middleware to put async things like API calls into actions. A common one is `redux-thunk` : https://redux.js.org/advanced/async-actions#async-action-creators – Jayce444 Jul 19 '18 at 12:44
  • Thank you, but I prefer to stay with classical approach for now. – tesicg Jul 19 '18 at 12:49
  • 2
    You can't do async stuff in vanilla Redux. You'll need something like `redux-thunk` or `redux-saga`. – Jayce444 Jul 19 '18 at 13:04

2 Answers2

1

HTTP calls in Redux are considered side effects. They are not a part of Redux itself, which is only a state management library. Therefore you'll have to use another library in addition to Redux, of which the easiest one is redux-thunk.

Using redux-thunk you can define a side effect which is essentially a function that can dispatch multiple times. For example:

import { LOAD_DATA } from '../constants/action-types';

export const getOrders = () => async (dispatch) => {
    try {
        const response = await axios.get("http://localhost:1234/api/orders");
        dispatch(loadData(response.data))
    } catch (e) {
        /* ... */
    }
}

export const loadData = orders => ({
type: LOAD_DATA,
payload: orders
})
Niels de Bruin
  • 705
  • 5
  • 15
1

Jayce444 is correct, you should use redux-thunk. I would consider that the canonical way to do this.

check out this answer : https://stackoverflow.com/a/34458710/8896573

if you want to keep this elementary, forget about mapDispatchToProps (still do mapStateToProps) and in your axios response just call this.props.dispatch(loadData (orders))

Then because of the structure of your mapStateToProps, your 'orders' are available in your component as this.props.orders :)

Joey Gough
  • 2,753
  • 2
  • 21
  • 42
  • Do you mean to call this.props.dispatch(loadData(orders)) from "axios" call inside componentDidMount in OrdersTable component? – tesicg Jul 19 '18 at 14:38
  • ye i would try that. I haven't tried it. but I would try it. But eventually you should try redux-thunk. have you tried it? – Joey Gough Jul 19 '18 at 20:01