【问题标题】:Redux Store and nested JSON from Axios APIRedux Store 和来自 Axios API 的嵌套 JSON
【发布时间】:2018-07-02 12:37:37
【问题描述】:

我尝试了此代码的所有可能变体,但我并没有真正设法将 API 提取到我的数据存储中。我完全被困住了,希望能得到一些帮助。 我想我只是不明白这个结构的基本部分,我真的很想了解它是如何正常工作的。

数据看起来像这样 - 它基本上是一个带有一些嵌套元素的简单 JSON(来自 django restframework API):

编辑 2(将 JSON 更改为 axios API/Redux 操作的屏幕截图)

我的 Redux 操作 - 运行良好。 console.log 从上面准确提取数据(输入正确):

    // ./action/plan.js 

import axios from 'axios';

    export function fetchBudgets(){
      return function(dispatch){
        axios.get("/api/budgets/")
        .then((response) => {
          console.log(response)
          dispatch({ type: "FETCH_BUDGETS", budgets: response.data})
        })
        .catch((err) => {
          dispatch({type: "FETCH_DATA_REJECTED", budgets: err})
        })
      }
    }

所以到目前为止,一切似乎都很好。问题从减速器开始——因为我不确定如何为减速器建模以使用嵌套数据。

我的减速机:

       // ./reducer/plan.js

        const initialState = {}


export default function budgets(state=initialState, action) {


    switch (action.type) {

        case 'FETCH_BUDGETS':
        console.log(action)
            return {
                    ...state,
                        id: action.budgets.id,
                        value_jan: action.budgets.value_jan,
                        value_feb: action.budgets.value_feb,
                        value_mar: action.budgets.value_mar,
                        value_apr: action.budgets.value_apr,
                        value_may: action.budgets.value_may,
                        value_jun: action.budgets.value_jun,
                        value_jul: action.budgets.value_jul,
                        value_aug: action.budgets.value_aug,
                        value_sep: action.budgets.value_sep,
                        value_oct: action.budgets.value_oct,
                        value_nov: action.budgets.value_nov,
                        value_dec: action.budgets.value_dec,
                        p_version: action.budgets.p_version,
                        entry_time: action.budgets.entry_time,
                        campaign: {
                            ...state.campaign, ...action.budgets.campaign
                        },
                        segment: {
                            ...state.segment, ...action.budgets.segment
                        },
                        touch_point: {
                            ...state.touch_point, ...action.budgets.touch_point
                        },
                        year: {
                            ...state.year, ...action.budgets.year
                        },
                        user: {
                            ...state.user, ...action.budgets.user
                        }
                    }

        default:
            return state
    }



}

我已经无法在此处显示数据 - 所以 this.props.fetchBudgets() 似乎没有获取任何数据。

我的 .jsx 应用程序

//./container/PlanContainer.jsx

      import React, { Component } from 'react';
    import {connect} from 'react-redux';


    import BootstrapTable from 'react-bootstrap-table-next';
    import cellEditFactory from 'react-bootstrap-table2-editor';

    import 'jquery';
    import 'popper.js'
    import 'bootstrap';
    import 'underscore'
    import _ from 'lodash'


    import {plan} from "../actions";


    const columns = [
                          { dataField: 'id', text: 'ID', hidden: true}, 
                          { dataField: 'year', text: 'Year', editable: false}, 
                          { dataField: 'segment', text: 'Segment', editable: false},
                          { dataField: 'campaign.name',text: 'Campaign', editable: false},
                          { dataField: 'touch_point',text: 'Touchpoint', editable: false},
                          { dataField: 'value_jan',text: 'Jan'},
                          { dataField: 'value_feb',text: 'Feb'},
                          { dataField: 'value_mar',text: 'Mar'},
                          { dataField: 'value_apr',text: 'Apr'},
                          { dataField: 'value_may',text: 'May'},
                          { dataField: 'value_jun',text: 'Jun'},
                          { dataField: 'value_jul',text: 'Jul'},
                          { dataField: 'value_aug',text: 'Aug'},
                          { dataField: 'value_sep',text: 'Sep'},
                          { dataField: 'value_oct',text: 'Oct'},
                          { dataField: 'value_nov',text: 'Nov'},
                          { dataField: 'value_dec',text: 'Dec'},
                          { dataField: 'user',text: 'User'},
                        ];

    const RemoteCellEdit = (props) => {

      const { columns, data, keyField } = props

      const cellEdit = {
        mode: 'click',
        errorMessage: props.errorMessage,
        blurToSave: true
      };

      return (
        <div>
          <BootstrapTable
            remote={ { cellEdit: true } }
            keyField = { keyField }
            data={ data }
            columns={ columns }
          />


        </div>
      );
    };

    class PlanContainer extends React.Component {

      componentDidMount() {

        this.props.fetchBudgets();
        console.log(this.props.fetchBudgets())

      }




      render() {
        return (
          <div>
          <RemoteCellEdit
            data={ this.props.budgets }
            columns = { columns }
            keyField = 'id'
          />



        </div>
        );
      }
    }


    const mapStateToProps = state => {
        return {
            budgets: state.budgets,
        }
    }

    const mapDispatchToProps = dispatch => {
      return {
        fetchBudgets: () => {
          dispatch(plan.fetchBudgets());
        },
      }
    }



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

最后,我的商店 - 根据 console.log 没有通过:

// .Planning.jsx    

import React from "react"
    import { hot } from 'react-hot-loader'
    import { render } from "react-dom"
    import {
      createStore,
      compose,
      applyMiddleware,
      combineReducers,
    } from "redux"
    import { Provider } from "react-redux"
    import thunk from "redux-thunk"

    import PlanContainer from "./containers/PlanContainer"
    import reducerApp from "./reducers";
    import Sidebar from "./components/Sidebar"

    import axios from 'axios';
    import axiosMiddleware from 'redux-axios-middleware';



    let store = createStore(reducerApp, applyMiddleware(thunk, axiosMiddleware(axios)));

    console.log(store)

    class Planning extends React.Component {
      render() {
        return (

          <Sidebar>
            <Provider store={store}>
              <PlanContainer />
            </Provider>
          </Sidebar>

        )
      }
    }

    render(<Planning />, document.getElementById('Planning'))

再次感谢我,因为我已经在这个问题上停留了很长一段时间,我真的很想了解如何正确地做到这一点。

编辑: 这是我的浏览器的屏幕截图:第一个元素是商店,第二个是 .jsx 应用程序,第三个是动作(看起来非常好),第四个是减速器中的动作。

【问题讨论】:

  • 您的操作是{type: "FETCH_BUDGETS", budgets: response.data},在reducer 中您有return [...state, action.budgets.data],其中action.budgets === response.data(我假设语法错误是拼写错误)。对我来说,这看起来像你在减速器中有一个额外的.data,你可能不需要。
  • 嗨 Yoshi,谢谢 - 你完全正确。但不幸的是,它并没有解决我的问题。我用浏览器控制台的图片更新了我的帖子 - 第一个元素是商店,它实际上并没有从减速器(第 4 个元素)收到任何东西。
  • 您处理的实际数据类型是什么?在您的减速器中,您将数据作为数组处理,那么它不应该是[...state, ...action.budgets.data](或类似的)。否则action.budgets.data 将简单地插入到...state 之后的下一个索引处。也就是说,您可以尝试简单地返回 action.budgets 作为新状态。
  • 我添加了 Axios API 从数据库中获取的任何内容的屏幕截图 - 它还显示了我正在使用的数据类型。 API 工作得很好——我猜我在减速器中遗漏了一些东西。 reducer 当前是 [...state, ...action.budgets.data] - 但问题仍然存在。
  • 这很奇怪,我真的不知道是什么导致了这个问题。我认为这不会解决它,但您应该在 componentDidMount 生命周期方法中进行 api 调用

标签: reactjs redux django-rest-framework axios react-bootstrap-table


【解决方案1】:

PlanContainer 搞砸了。方法如下:

componentDidMount() {
    this.budgets = this.props.fetchBudgets();   
  }

this.budgets 指向 this.props.fetchBudgets() 返回的值,在这种情况下,它是一个 Promise,而不是实际数据。

state = {
      data: this.budgets
    };

state 现在持有承诺,而不是数据。

render() {
    return (
      <div>
      <RemoteCellEdit
        data={ this.state.data }
        ...
  }

所以data 这里不是实际数据,而是承诺。

之所以会出现混乱,是因为您将 redux 状态与反应状态混合在一起。使用其中一个,而不是两者都使用(对此有例外,但在此特定情况下没有)。

PlanContainer 存在更多问题,尚不清楚它们是真正的问题,还是只是 OP 中代码遗漏的结果。

请参阅下面的注释:

class PlanContainer extends React.Component {

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

  constructor(props) {
    ... // removed for brevity, use the same code as you have right now
  }



  render() {
    return (
      <div>
      <RemoteCellEdit
        data={ this.props.budgets}
        columns = { this.columns }
        keyField = 'id'
        errorMessage={ /* should come from props.data or similar - it's not in state */ }
      />

      <tbody>
      {this.props.budgets} /* not sure what this is for - I assumed RemoteCellEdit is the one rendering the data */
      </tbody>

    </div>
    );
  }
}

解决这些问题应该会让您走上正确的道路。祝你好运!

【讨论】:

  • 现在 reducer 返回一个对象而不是数组。你确定要这样做吗?你不能那样渲染表格。另外,附注:如果您的目标是显示 API 返回的预算,那么您不应该合并/连接它的现有状态。在你的减速器中,你可以简单地返回action.budgets
  • 另外,如果你能创建一个代码框(你可以 fork 这个:codesandbox.io/s/jpn9m4rwr9)并使用类似 jsonapi 或 mockaxios 的东西来伪造 axios 调用,那将会很有帮助。
  • 非常感谢!我会尝试将见解转移到我的代码中 - 尝试尽快更新。
  • changing the reducer index, adding the separate store(都类似于您发布的代码框)和计划减速器中的implementing Object spread 起到了作用。再次,非常感谢!
猜你喜欢
  • 2020-11-27
  • 2016-03-21
  • 1970-01-01
  • 2019-05-12
  • 2020-02-14
  • 2019-05-06
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
相关资源
最近更新 更多