【问题标题】:React + Redux + Axios not loading component after actions is createdReact + Redux + Axios 在创建动作后不加载组件
【发布时间】:2018-10-22 17:06:01
【问题描述】:

我正在尝试使用我创建的 API,我遵循了我之前使用过的代码,但是当加载组件时,由于 json 列表为空,它显示为空列表,我可以在记录之后正在加载列表,但组件上没有刷新或任何内容。我尝试添加一个验证,即如果列表的长度为 cero,则不打印任何内容,但这会导致错误。我可以猜到中间件存在问题(我使用的是 redux-promise)。如您所见,我在应用程序定义中添加了中间件,我看不出它缺少什么任何想法?这是我的代码:

actions/index.js:

import axios from 'axios';

export const FETCH_TESTS = 'FETCH_TESTS';
const ROOT_URL = 'http://some-working-api-entry.com';

export function fetchTests(){
  const request = axios.get(`${ROOT_URL}/tests/?format=json`);
  return {
    type: FETCH_TESTS,
    payload: request
  }
}

reducers/reducer_tests.js

import { FETCH_TESTS } from '../actions/index';

export default function(state = [], action){
  switch (action.type) {
    case FETCH_TESTS:
      return [action.payload.data, ...state]; //ES6 syntaxis\   

 }
 return state;
}

actions/index.js

import { combineReducers } from 'redux';
import TestsReducer from './reducer_tests';

const rootReducer = combineReducers({
  tests: TestsReducer
});

export default rootReducer;

容器/list_tests.js

import _ from 'lodash';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchTests } from '../actions';

class TestList extends Component{

    componentDidMount(){
        this.props.fetchTests();
    }

    renderTest(){
      return _.map(this.props.tests, test => {
        return (
          <tr key={test.id}>
            <td>{test.id}</td>
            <td>{test.col1}</td>
            <td>{test.col2}</td>
            <td>{test.col3}</td>
            <td>{test.col4}</td>
        </tr>
        );
      });
  }

  render(){
    return (
      <table className="table table-hover">
        <thead>
          <tr>
            <th>ID</th>
            <th>Col 1</th>
            <th>Col 2</th>
            <th>Col 3</th>
            <th>Col 4</th>
          </tr>
        </thead>
        <tbody>
          { this.renderTest() }
        </tbody>
      </table>
    );
  }
}

function mapStateToProps(state){
    return {tests: state.tests}
  }
//export default connect(mapStateToProps)(TestList)
export default connect(mapStateToProps, { fetchTests})(TestList);

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import ReduxPromise from 'redux-promise';

import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);

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

package.json

{
  "name": "someapp",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "axios": "^0.18.0",
    "react": "^16.3.2",
    "react-dom": "^16.3.2",
    "react-redux": "^5.0.7",
    "react-scripts": "1.1.4",
    "redux": "^4.0.0",
    "redux-logger": "^3.0.6",
    "redux-promise": "^0.5.3",
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

编辑: 来自动作创建者(数组包含 api 列表入口点上的唯一对象):

config: Object { timeout: 0, xsrfCookieName: "XSRF-TOKEN", xsrfHeaderName: "X-XSRF-TOKEN", … }
​
data: Array [ {…} ]
​
headers: Object { "content-type": "application/json" }
​
request: XMLHttpRequest { readyState: 4, timeout: 0, withCredentials: false, … }

​ 状态:200 ​​​ 状态文本:“确定” ​​​ proto:对象 { … }

来自减速器:

payload:[object Object]

如果我在容器上记录测试道具,首先它会记录一个空数组 [],然后它会记录一个长度为 1 的数组

【问题讨论】:

  • 该动作是否转到reducer?您可以通过以下方式检查网络请求的输出:axios.get(${ROOT_URL}/tests/?format=json).then(result=&gt;console.log("result:",result)||result);
  • 你能用 axios.get 的输出和你的 reducer 中记录每个操作的 console.log 更新问题吗?
  • 肯定没有更新,因为你对道具什么都不做?你打电话给mapStateToProps,但不要在componentDidReceiveProps 中找到他们。您应该在此处将它们设置为您的组件状态,这将导致组件重新渲染。

标签: javascript reactjs redux redux-promise


【解决方案1】:
const request = axios.get(`${ROOT_URL}/tests/?format=json`);
 // here is your issue because axios returns promise.

像这样创建一个 doGet 方法。

export function doGet(url, onSuccess, onFailure) {

        return axios.get(url)
            .then((response) => {
                if (onSuccess) {
                    onSuccess(response);
                }

                return response.data || {};
            })
            .catch((error) => {
                if (onFailure) {
                    onFailure(error);
                }
            });
    }

然后在你的componentDidMount 上调用这个方法,比如:

doGet(
   'your/api/url',
   (response) => console.log('Api success callback', response),
   (error) => console.log('error callback', error)
)

【讨论】:

  • 对不起,你错了。 axios.get 返回一个 promise,应该由 redux-promise 处理。为已经是承诺的东西添加回调选项是没有意义的。
  • 我没看错,我为所有get请求创建了一个通用的doGet方法。
  • 我同意调用 get 函数而不是直接使用 axios(可能来自许多不同的地方)是更好的设计,但这不是当前的问题。使用 redux-promise 中间件时,为有效负载返回承诺非常适合操作
  • 好的,我同意你的看法。
【解决方案2】:

您必须调用调度员来更新商店。

containers/list_tests.js

const mapDispatchToProp = dispatch => ({
      fetchTests : () => dispatch(fetchTests())
})

export default connect(mapStateToProps, mapDispatchToProp )(TestList);

编辑 1:发现另一个问题。

export function fetchTests(){
  return axios.get(`${ROOT_URL}/tests/?format=json`)
       .then(res => {
             return {
                type: FETCH_TESTS,
                 payload: res.data
              }
        });

}

【讨论】:

  • 我认为动作绑定已经用export default connect(mapStateToProps, { fetchTests})(TestList);正确完成了不确定res.data是否有帮助,OP需要发布响应是什么以及它是否成功。
  • 我不知道它是如何正确的 => export default connect(mapStateToProps, { fetchTests})(TestList); .... 他想更新 redux 存储。如果我们不调用dispatch 那么redux store 将如何更新?可能我没明白你的意思。 @HMR
  • 是的,可以pass an object:如果传递了一个对象,那么它里面的每个函数都被假定为一个Redux action creator。具有相同函数名的对象,但每个动作创建者都包装在一个调度调用中以便可以直接调用它们,将被合并到组件的 props 中。
猜你喜欢
  • 2019-07-08
  • 2020-11-24
  • 2017-10-13
  • 2022-01-27
  • 2017-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-25
相关资源
最近更新 更多