首页 > 解决方案 > 如何分配 react redux state api 使用 axios 获取数据

问题描述

我使用 react 16+ 和 redux get jsonplaceholder fake data 来分配帖子状态但不工作。无法分配状态。如何使用 concat 方法将 json 值分配给状态。我也检查了生命周期方法,但无法得到答案。

减速器

import * as actiontypes from './actions';
import axios from 'axios';

const initalstate = {
    counter: 0,
    posts: []
};

const reducer = (state = initalstate, action ) => {
    switch (action.type) {
        case actiontypes.actionFetchPost:
            axios.get('https://jsonplaceholder.typicode.com/posts')
                .then(res => {
                    return {
                        ...state,
                        posts: state.posts.concat(res.data)
                    }
                });
            break;
        default :
            return state;
    }
};

export default reducer;

标签: javascriptreactjsredux

解决方案


Redux reducer 必须是纯函数,这意味着它们不应包含任何副作用,例如调用 api。

您需要使用redux-thunk包在动作创建者中调用 api。

代码沙盒

一个示例动作创建者:

import {
  FETCH_POSTS_STARTED,
  FETCH_POSTS_FAILURE,
  FETCH_POSTS_SUCCESS
} from "./actionTypes";
import axios from "axios";

export const fetchPosts = () => {
  return dispatch => {
    dispatch(fetchPostsStarted());

    axios
      .get("https://jsonplaceholder.typicode.com/posts")
      .then(res => {
        dispatch(fetchPostsSuccess(res.data));
      })
      .catch(err => {
        dispatch(fetchPostsFailed(err.message));
      });
  };
};

const fetchPostsStarted = () => {
  return {
    type: FETCH_POSTS_STARTED,
    payload: {
      isLoading: true
    }
  };
};

const fetchPostsSuccess = posts => {
  return {
    type: FETCH_POSTS_SUCCESS,
    payload: {
      posts
    }
  };
};

const fetchPostsFailed = error => {
  return {
    type: FETCH_POSTS_FAILURE,
    payload: {
      error
    }
  };
};

和减速器文件:

import {
  FETCH_POSTS_STARTED,
  FETCH_POSTS_SUCCESS,
  FETCH_POSTS_FAILURE
} from "../actions/actionTypes";

const initialState = {
  posts: [],
  loading: false,
  error: null
};

export default function(state = initialState, action) {
  switch (action.type) {

    case FETCH_POSTS_STARTED:
      return {
        ...state,
        loading: true
      };
    case FETCH_POSTS_SUCCESS:
      return {
        ...state,
        loading: false,
        error: null,
        posts: action.payload.posts
      };
    case FETCH_POSTS_FAILURE:
      return {
        ...state,
        loading: false,
        error: action.payload.error
      };
    default:
      return state;
  }
}

在商店中,我们像这样使用 redux-thunk:

import { createStore, compose, applyMiddleware, combineReducers } from "redux";
import reduxThunk from "redux-thunk";
import postsReducers from "./reducers/postsReducers";

const rootReducer = combineReducers({
  posts: postsReducers
});

const store = createStore(rootReducer,  compose(applyMiddleware(reduxThunk)));

export default store;

帖子组件:

import React, { Component } from "react";
import { connect } from "react-redux";
import { fetchPosts } from "./store/actions/postsActions";

class Posts extends Component {
  componentDidMount() {
    this.props.fetchPosts();
  }

  render() {

    const { posts, loading, error } = this.props;

    return (
      <div>
        {loading && <div>LOADING...</div>}
        {error && <div>{error}</div>}
        <ul>
          {posts.map(post => (
            <li key={post.id}>{post.title}</li>
          ))}
        </ul>
      </div>
    );
  }
}

const mapStateToProps = state => {
  const { posts, loading, error } = state.posts;
  return {
    posts,
    loading,
    error
  };
};

export default connect(
  mapStateToProps,
  {
    fetchPosts
  }
)(Posts);

索引.js

import ReactDOM from "react-dom";
import store from "./store/store";
import { Provider } from "react-redux";
import Posts from "./Posts";

function App() {
  return (
    <div className="App">
      <Posts />
    </div>
  );
}

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


推荐阅读