简体   繁体   中英

Updating React Component State after Axios Call using Redux

I'm working to learn React and Redux. As part of this, I'm creating a simple app that retrieves a list of items from my REST API. To query this REST API, I'm using Axios. Currently, I do not understand how to actually update the state in the store. The Redux examples are confusing.

At this time, my app has the following:

/my-app
  /actions
    items.js
  /components
    items.js
  App.css
  App.js
  index.css
  index.js
  store.js

/my-app/actions/items.js

import axios from 'axios';

export GET_ITEMS = 'GET_ITEMS';

export const getItems = (count) => {
  axios.get('https://my-app.com/items')
    .then(function(response) {
      console.log(response.results);
      // need to set "response.results" to the value in the store
    }
};

/components/items.js

import React from 'react';

import { getItems } from '../actions/items';

class Items extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      items: []
    }
  }

  onButtonClick = () => {
    getItems(5);
  }

  render() {
    return {
      <div>
        <button type="button" onClick={this.onButtonClick}>Load Items</button>
        <br />

        {this.state.items.map((item) => {
          <div>{item.name}</div>
        ))}
      </div>
    }
  }
}

App.js

import React from 'react';

import Items from './components/items';

function App() {
  return {
    <div>
      <Items></Items>
    </div>
  };
}

export default App;

/store.js

import { createStore } from 'redux';

import { GET_ITEMS } from './actions/items';

let initialState = {
  items: [
    {
      id:1,
      name:'Item A',
      description: 'This is a pre-populated item for testing purposes.'
    }
  ]
}

function itemsReducer(state, action) {
  switch (action.type) {
    case GET_ITEMS:
      break;
    default:
      return state;
  }
}

let store = createStore(itemsReducer, initialState);
export default store;

index.js

import React from 'react';
import ReactDOM from 'react-dom';

import { Provider } from 'react-redux';
import store from './store';

import App from './App';

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

When I run this, I see a screen with a button. I can click the button, however, I do not see the items displayed on the screen. If I look in the console window, I can see the items printed via the console.log statement.

How do I take the items returned from the REST API and a) set those items in the store and b) use the store items in my component?

Thank you so much for your help! Redux has been a challenge.

To make things easy, I will keep this folder structure

/my-app
  /API
    index.js
  /state
     action-types.js
    /actions
       items.js
    /reducers
       items.js
  /components
    /items
       ItemComponent.js

I like to separate my API from state to offer better separation of concerns/control

API/index.js

import axios from 'axios';

const BASE_URL = 'https://my-app.com/items';

export const getItems = () => {
  axios
    .get(`${BASE_URL}/items`)
    .then(response => response.data)
    .catch(error => error);
};

Reasons I like this approach

  • this allows call to getItems API endpoint without calling getItems action and state update
  • In case you decide to use any different API library in place of axios , you don't need to modify all your action files

action-types.js

  export const GET_ITEMS = 'GET_ITEMS';

/actions/item.js

import * as ACTION_TYPES from '../action-types';
import * as API from '../../API';

const getItems = async count => {
  const getItemsResponse = await API.getItems();

  return {
    type: ACTION_TYPES.GET_ITEMS,
    payload: {
      items: getItemsResponse.data,
      count
    }
  };
};

export default getItems;

/reducers/item.js

import * as ACTION_TYPES from '../action-types';

const initialState = {
  items: [
    {
      id:1,
      name:'Item A',
      description: 'This is a pre-populated item for testing purposes.'
    }
  ]
}

const itemsReducer = (state, action) => {
  switch (action.type) {
    case ACTION_TYPES.GET_ITEMS:
      const { items } = action.payload;
      return { ...state, items }
      break;
    default:
      return state;
  }
}

Lastly, you can wrap connect from react-redux around the ItemComponent.js . The code below should be added to what already exist in the file ItemComponent.js

const mapDispatchToPtops = {
    getItems
}

const mapStateToProp = state =>({
   items: state.itemsReducer.items
})

export default connect(mapStateToProp, mapDispatchToPtops)(ItemComponent)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM