Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 如何在REACT和FLUX中创建API调用_Reactjs_Reactjs Flux - Fatal编程技术网

Reactjs 如何在REACT和FLUX中创建API调用

Reactjs 如何在REACT和FLUX中创建API调用,reactjs,reactjs-flux,Reactjs,Reactjs Flux,我是一个新的反应和流量,我有一个艰难的时间试图找出如何从服务器加载数据。我能够从本地文件加载相同的数据,没有任何问题 首先,我有一个控制器视图(controller view.js),它将初始状态传递给一个视图(view.js) 控制器视图.js var viewBill = React.createClass({ getInitialState: function(){ return { bill: BillStore.getAllBill() }; }, re

我是一个新的反应和流量,我有一个艰难的时间试图找出如何从服务器加载数据。我能够从本地文件加载相同的数据,没有任何问题

首先,我有一个控制器视图(controller view.js),它将初始状态传递给一个视图(view.js)

控制器视图.js

var viewBill = React.createClass({
getInitialState: function(){
    return {
        bill: BillStore.getAllBill()
    };
},
render: function(){
    return (
        <div>
            <SubscriptionDetails subscription={this.state.bill.statement} />
        </div>
    );
}
 });
 module.exports = viewBill;
var subscriptionsList = React.createClass({
propTypes: {
    subscription: React.PropTypes.array.isRequired
},
render: function(){

   return (
        <div >
            <h1>Statement</h1>
            From: {this.props.subscription.period.from} - To {this.props.subscription.period.to} <br />
            Due: {this.props.subscription.due}<br />
            Issued:{this.props.subscription.generated}
        </div>
    );
}
 });
 module.exports = subscriptionsList;
var InitialiseActions = {
initApp: function(){
    Dispatcher.dispatch({
        actionType: ActionTypes.INITIALISE,
        initialData: {
            bill: BillApi.getBillLocal() // I switch to getBillServer for date from server
        }
    });
}
};
module.exports = InitialiseActions;
var BillApi = {
getBillLocal: function() {
    return billed;
},
getBillServer: function() {
    return $.getJSON('https://theurl.com/stuff.json').then(function(data) {

        return data;
    });
}
};
module.exports = BillApi;
var _bill = [];
var BillStore = assign({}, EventEmitter.prototype, {
addChangeListener: function(callback) {
    this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback) {
    this.removeListener(CHANGE_EVENT, callback);
},
emitChange: function() {
    this.emit(CHANGE_EVENT);
},
getAllBill: function() {
    return _bill;
}
});

Dispatcher.register(function(action){
switch(action.actionType){
    case ActionTypes.INITIALISE:
        _bill = action.initialData.bill;
        BillStore.emitChange();
        break;
    default:
        // do nothing
}
});

module.exports = BillStore;
然后我的数据API看起来像这样

// InitialActions.js


var InitialiseActions = {
initApp: function(){
    BillApi.getBill(function(result){
      // result from getJson is available here
      Dispatcher.dispatch({
          actionType: ActionTypes.INITIALISE,
          initialData: {
              bill: result
          }
      });
    });
}
};
module.exports = InitialiseActions;

//api.js

var BillApi = {
    getBillLocal: function() {
        console.log(biller);
        return biller;
    },
    getBill: function(callback) {
      $.getJSON('https://theurl.com/stuff.json', callback);
    }
};
api.js

var viewBill = React.createClass({
getInitialState: function(){
    return {
        bill: BillStore.getAllBill()
    };
},
render: function(){
    return (
        <div>
            <SubscriptionDetails subscription={this.state.bill.statement} />
        </div>
    );
}
 });
 module.exports = viewBill;
var subscriptionsList = React.createClass({
propTypes: {
    subscription: React.PropTypes.array.isRequired
},
render: function(){

   return (
        <div >
            <h1>Statement</h1>
            From: {this.props.subscription.period.from} - To {this.props.subscription.period.to} <br />
            Due: {this.props.subscription.due}<br />
            Issued:{this.props.subscription.generated}
        </div>
    );
}
 });
 module.exports = subscriptionsList;
var InitialiseActions = {
initApp: function(){
    Dispatcher.dispatch({
        actionType: ActionTypes.INITIALISE,
        initialData: {
            bill: BillApi.getBillLocal() // I switch to getBillServer for date from server
        }
    });
}
};
module.exports = InitialiseActions;
var BillApi = {
getBillLocal: function() {
    return billed;
},
getBillServer: function() {
    return $.getJSON('https://theurl.com/stuff.json').then(function(data) {

        return data;
    });
}
};
module.exports = BillApi;
var _bill = [];
var BillStore = assign({}, EventEmitter.prototype, {
addChangeListener: function(callback) {
    this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback) {
    this.removeListener(CHANGE_EVENT, callback);
},
emitChange: function() {
    this.emit(CHANGE_EVENT);
},
getAllBill: function() {
    return _bill;
}
});

Dispatcher.register(function(action){
switch(action.actionType){
    case ActionTypes.INITIALISE:
        _bill = action.initialData.bill;
        BillStore.emitChange();
        break;
    default:
        // do nothing
}
});

module.exports = BillStore;
这就是商店 store.js

var viewBill = React.createClass({
getInitialState: function(){
    return {
        bill: BillStore.getAllBill()
    };
},
render: function(){
    return (
        <div>
            <SubscriptionDetails subscription={this.state.bill.statement} />
        </div>
    );
}
 });
 module.exports = viewBill;
var subscriptionsList = React.createClass({
propTypes: {
    subscription: React.PropTypes.array.isRequired
},
render: function(){

   return (
        <div >
            <h1>Statement</h1>
            From: {this.props.subscription.period.from} - To {this.props.subscription.period.to} <br />
            Due: {this.props.subscription.due}<br />
            Issued:{this.props.subscription.generated}
        </div>
    );
}
 });
 module.exports = subscriptionsList;
var InitialiseActions = {
initApp: function(){
    Dispatcher.dispatch({
        actionType: ActionTypes.INITIALISE,
        initialData: {
            bill: BillApi.getBillLocal() // I switch to getBillServer for date from server
        }
    });
}
};
module.exports = InitialiseActions;
var BillApi = {
getBillLocal: function() {
    return billed;
},
getBillServer: function() {
    return $.getJSON('https://theurl.com/stuff.json').then(function(data) {

        return data;
    });
}
};
module.exports = BillApi;
var _bill = [];
var BillStore = assign({}, EventEmitter.prototype, {
addChangeListener: function(callback) {
    this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback) {
    this.removeListener(CHANGE_EVENT, callback);
},
emitChange: function() {
    this.emit(CHANGE_EVENT);
},
getAllBill: function() {
    return _bill;
}
});

Dispatcher.register(function(action){
switch(action.actionType){
    case ActionTypes.INITIALISE:
        _bill = action.initialData.bill;
        BillStore.emitChange();
        break;
    default:
        // do nothing
}
});

module.exports = BillStore;
如前所述,当我在actions中使用BillApi.getBillLocal()本地加载数据时,一切正常。但是当我更改为BillApi.getBillServer()时,控制台中会出现以下错误

Warning: Failed propType: Required prop `subscription` was not specified in     `subscriptionsList`. Check the render method of `viewBill`.
Uncaught TypeError: Cannot read property 'period' of undefined
我还向BillApi.getBillServer()添加了一个console.log(数据),可以看到数据是从服务器返回的。但它在控制台中收到警告后显示,我认为这可能是问题所在。有人能给我一些建议或帮我解决吗?抱歉发这么长的帖子

更新


我对api.js文件做了一些更改(检查这里的更改和DOM错误plnkr.co/edit/HoXszori3HUAwUOHzPLG),因为有人认为问题在于我如何处理承诺。但这似乎仍然是在DOM错误中看到的相同问题。

这是一个异步问题。使用
$.getJSON().then()
是不够的。由于它返回一个promise对象,因此必须在调用时通过执行类似于
api.getBill()的操作来处理promise

我用下面的代码做了一个测试:

function searchSpotify(query) {
  return $.getJSON('http://ws.spotify.com/search/1/track.json?q=' + query)
  .then(function(data) {
    return data.tracks;
  });  
}

searchSpotify('donald trump')
.then(function(tracks) {
  tracks.forEach(function(track) {
    console.log(track.name);
  });
});

另一种方法是在处理数据之前检查订阅的道具是否存在

尝试修改代码,使其看起来有点像这样:

render: function(){

  var subscriptionPeriod = '';
  var subscriptionDue = ['',''];
  var subscriptionGenerated = '';

  if(this.props.subscription !== undefined){
       subscriptionPeriod = this.props.subscription.period;
       subscriptionDue = [this.props.subscription.due.to,this.props.subscription.due.from];
       subscriptionGenerated = this.props.subscription.generated;
  }

  return (
    <div >
        <h1>Statement</h1>
        From: {subscriptionPeriod[0]} - To {subscriptionPeriod[1]} <br />
        Due: {subscriptionDue}<br />
        Issued:{subscriptionGenerated}
    </div>
);
}
import keyMirror from 'keymirror';


import ApiService from '../../lib/api';
import Dispatcher from '../dispatcher/dispatcher';
import config from '../env/config';


export let ActionTypes = keyMirror({
  GetAllBillPending: null,
  GetAllBillSuccess: null,
  GetAllBillError: null
}, 'Bill:');

export default {
  fetchBills () {
    Dispatcher.dispatch(ActionTypes.GetAllBillPending);

    YOUR_API_CALL
      .then(response => {
        //fetchs your API/service call to fetch all Bills
        Dispatcher.dispatch(ActionTypes.GetAllBillSuccess, response);
      })
      .catch(err => {
        //catches error if you want to
        Dispatcher.dispatch(ActionTypes.GetAllBillError, err);
      });
  }
};
render:function(){
var subscriptionPeriod='';
var subscriptionDue=['',];
var subscriptionGenerated='';
if(this.props.subscription!==未定义){
subscriptionPeriod=this.props.subscription.period;
subscriptionDue=[this.props.subscription.due.to,this.props.subscription.due.from];
subscriptionGenerated=this.props.subscription.generated;
}
返回(
陈述
从:{subscriptionPeriod[0]}-到{subscriptionPeriod[1]}
到期:{subscriptionDue}
已发布:{subscriptionGenerated} ); }
在返回之前的渲染函数中,尝试添加以下内容: if(this.props.subscription!=未定义){ //在这里做点什么 }


由于您的数据更改顶级组件的状态,它将在定义订阅道具的数据后重新触发渲染

如果我理解正确,你可以试试这样的东西

// InitialActions.js


var InitialiseActions = {
initApp: function(){
    BillApi.getBill(function(result){
      // result from getJson is available here
      Dispatcher.dispatch({
          actionType: ActionTypes.INITIALISE,
          initialData: {
              bill: result
          }
      });
    });
}
};
module.exports = InitialiseActions;

//api.js

var BillApi = {
    getBillLocal: function() {
        console.log(biller);
        return biller;
    },
    getBill: function(callback) {
      $.getJSON('https://theurl.com/stuff.json', callback);
    }
};
$.getJSON不会从http请求返回值。它使回调函数可以使用它。
此处详细解释了其背后的逻辑:

从代码中可以看出,预期的流类似于:

  • 某些组件触发初始化操作
  • 初始化操作调用API
  • 等待来自服务器的结果(我认为这里是问题的症结所在:您的组件渲染在来自服务器的结果返回之前开始)
  • 然后将结果传递给商店
  • 它发出变化和
  • 触发重新渲染
在典型的通量设置中,我建议将其结构有所不同:

  • 某些组件调用API(,但尚未向dispatcher发出操作)
  • API执行
    getJSON
    ,并等待服务器结果
  • 只有在收到结果后,API才会使用收到的数据触发初始化操作
  • 存储响应操作,并使用结果更新自身
  • 然后释放变化
  • 哪个触发了重新渲染
我不太熟悉jquery、承诺和链接,但我认为这将大致转化为代码中的以下更改:

  • 控制器视图需要将更改侦听器添加到存储:添加一个
    componentDidMount()
    函数,该函数将事件侦听器添加到flux存储更改
  • 在控制器视图中,事件侦听器触发一个
    setState()
    函数,该函数从存储中获取最新的账单
  • dispatcher.dispatch()
    从您的actions.js移动到您的api.js(替换
    返回数据

这样,您的组件最初应该呈现一些“加载”消息,并在服务器中的数据进入后立即更新。

我将分离我的操作、存储和视图(React组件)

首先,我要这样实施我的行动:

render: function(){

  var subscriptionPeriod = '';
  var subscriptionDue = ['',''];
  var subscriptionGenerated = '';

  if(this.props.subscription !== undefined){
       subscriptionPeriod = this.props.subscription.period;
       subscriptionDue = [this.props.subscription.due.to,this.props.subscription.due.from];
       subscriptionGenerated = this.props.subscription.generated;
  }

  return (
    <div >
        <h1>Statement</h1>
        From: {subscriptionPeriod[0]} - To {subscriptionPeriod[1]} <br />
        Due: {subscriptionDue}<br />
        Issued:{subscriptionGenerated}
    </div>
);
}
import keyMirror from 'keymirror';


import ApiService from '../../lib/api';
import Dispatcher from '../dispatcher/dispatcher';
import config from '../env/config';


export let ActionTypes = keyMirror({
  GetAllBillPending: null,
  GetAllBillSuccess: null,
  GetAllBillError: null
}, 'Bill:');

export default {
  fetchBills () {
    Dispatcher.dispatch(ActionTypes.GetAllBillPending);

    YOUR_API_CALL
      .then(response => {
        //fetchs your API/service call to fetch all Bills
        Dispatcher.dispatch(ActionTypes.GetAllBillSuccess, response);
      })
      .catch(err => {
        //catches error if you want to
        Dispatcher.dispatch(ActionTypes.GetAllBillError, err);
      });
  }
};
下一个是我的存储,因此我可以跟踪api调用期间突然发生的所有更改:

class BillStore extends YourCustomStore {
  constructor() {
    super();

    this.bindActions(
      ActionTypes.GetAllBillPending, this.onGetAllBillPending,
      ActionTypes.GetAllBillSuccess, this.onGetAllBillSuccess,
      ActionTypes.GetAllBillError  , this.onGetAllBillError
    );
  }

  getInitialState () {
    return {
      bills : []
      status: Status.Pending
    };
  }

  onGetAllBillPending () {
    this.setState({
      bills : []
      status: Status.Pending
    });
  }

  onGetAllBillSuccess (payload) {
    this.setState({
      bills : payload
      status: Status.Ok
    });
  }

  onGetAllBillError (error) {
    this.setState({
      bills : [],
      status: Status.Errors
    });
  }
}


export default new BillStore();
最后,您的组件:

import React from 'react';

import BillStore from '../stores/bill';
import BillActions from '../actions/bill';


export default React.createClass({

  statics: {
    storeListeners: {
      'onBillStoreChange': BillStore
     },
  },

  getInitialState () {
    return BillStore.getInitialState();
  },

  onBillStoreChange () {
    const state = BillStore.getState();

    this.setState({
      bills  : state.bills,
      pending: state.status === Status.Pending
    });
  },

  componentDidMount () {
    BillActions.fetchBills();
  },

  render () {
    if (this.state.pending) {
      return (
        <div>
          {/* your loader, or pending structure */}
        </div>
      );
    }

    return (
      <div>
        {/* your Bills */}
      </div>
    );
  }

});
从“React”导入React;
从“../stores/bill”导入BillStore;
从“../actions/bill”导入BillActions;
导出默认的React.createClass({
静力学:{
storeListeners:{
“onBillStoreChange”:BillStore
},
},
getInitialState(){
返回BillStore.getInitialState();
},
onBillStoreChange(){
const state=BillStore.getState();
这是我的国家({
法案:州法案,
挂起:state.status==status.pending
});
},
组件安装(){
bellActions.fetchBills();
},
渲染(){
if(this.state.pending){
返回(
{/*加载程序或挂起结构*/}
);
}
返回(
{/*您的账单*/}
);
}
});

假设您实际上是从API获取数据,但是获取数据太晚,并且首先抛出错误,请尝试以下操作: 在controller-view.js中,添加以下内容:

componentWillMount: function () {
    BillStore.addChangeListener(this._handleChangedBills);
},

componentWillUnmount: function () {
    BillStore.removeChangeListener(this._handleChangedBills);
},

_handleChangedBills = () => {
    this.setState({bill: BillStore.getAllBill()});
}
在getInitialState函数中,提供一个空对象,该对象具有代码所期望的结构(具体来说,在其中包含一个“statement”对象)。大概是这样的:

getInitialState: function(){
return {
    bill: { statement:  [] }
};
},
Wh