一般状态问题与ReactJS&反流

时间:2015-11-28 10:58:08

标签: javascript reactjs

我对React很陌生,我正试图围绕着Reflux。

这是我的情景:

我目前有一个非常简单的应用程序,它从休息api调用一些歌曲数据,一旦被检索,它就存储在state.songs中(这发生在歌曲存储区的Init函数中):

var SongStore = Reflux.createStore({
  listenables: [SongActions],

  getInitialState: function() {
    return []
  },

  init: function() {
    request('http://127.0.0.1:1337/api/songs', function(error, response, body) {
      if (!error && response.statusCode == 200) {
        var content = JSON.parse(body);
        this.trigger(content);
      }
    }.bind(this));
  },

  onHandleClick: function(album_link) {
  // this.state.songs is undefined here??
  }

 });

以下是呈现歌曲数据的组件:

var Home = React.createClass({

mixins: [Reflux.connect(SongStore, 'songs')],

render: function() {
  return (
    <div className={'react-app-home'}>
      <div className="float-left">
        <div className="song-data">
          {this.state.songs.map(function(song) {
            return <div><p>{song.lyrics}</p></div>
          })}
        </div>
      </div>
      <div className="float-right">
        <AlbumList />
      </div>
    </div>
  );
 }
});

这一切都按预期工作。

我还有一个专辑列表,这些专辑在其自己的组件中呈现(并拥有它自己的商店),我试图在专辑中连接点击功能item,所以一旦点击了一个专辑标题,就会过滤this.state.songs并重新渲染歌曲组件。

我遇到的问题是当我尝试从歌曲商店访问this.state.songs时,它是未定义的(请参阅上面歌曲商店中的onHandleClick func)。

专辑列表组件:

var AlbumList = React.createClass({
  mixins: [Reflux.connect(AlbumStore, 'albums'),        
  Reflux.connect(SongStore, 'songs')],
  render: function() {
    return (
      <div className="album-list">
        {this.state.albums.map(function(album) {
        return <p onClick={SongStore.onHandleClick.bind(null, album.album_link)}>{album.album_name}</p>
        })}
      </div>
    );
  }
});

专辑列表商店:

var AlbumStore = Reflux.createStore({
  listenables: [AlbumActions],
  getInitialState: function() {
    return [];
  },

  onReload: function() {
    request('http://0.0.0.0:1337/api/albums', function(error, response, body) {
      if (!error && response.statusCode == 200) {
        var content = JSON.parse(body);
        this.trigger(content);
      }
    }.bind(this));
  },

  init: function() {
    this.onReload();
  }
});

任何人都可以帮助我吗?一些解释的答案很棒,所以我可以理解问题是什么。

谢谢!

1 个答案:

答案 0 :(得分:0)

您应该使用handleClick或从组件到商店的任何其他调用的操作。我还建议将你的api电话与商店分开。以下是https://github.com/calitek/ReactPatterns React.14 / ReFluxSuperAgent。

中的示例

app.js

'use strict';

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

import AppCtrl from './components/app.ctrl.js';
import Actions from './actions/api.Actions';
import ApiStore from './stores/Api.Store';

window.ReactDom = ReactDom;

Actions.apiInit();

ReactDom.render( <AppCtrl />, document.getElementById('react') );

请注意操作和api.store导入。 这是api.store。

import Reflux from 'reflux';

import Actions from '../actions/api.Actions';
import ApiFct from '../utils/sa.api';

let ApiStoreObject = {
  newData: {
    "React version": "0.14",
    "Project": "ReFluxSuperAgent",
    "currentDateTime": new Date().toLocaleString()
  },
  listenables: Actions,
  apiInit() { ApiFct.setData(this.newData); },
  apiInitDone() { ApiFct.getData(); },
  apiSetData(data) { ApiFct.setData(data); }
}
const ApiStore = Reflux.createStore(ApiStoreObject);
export default ApiStore;

apiInit在这里做一个setData但它可能是初始的get调用。 这就是api。

import request from 'superagent';

import apiActions from '../actions/api.Actions';
import saActions from '../actions/sa.Actions';

module.exports = {
  getData() { request.get('/routes/getData').end((err, res) => { this.gotData(res.body); }); },
  gotData(data) { saActions.gotData1(data); saActions.gotData2(data); saActions.gotData3(data); },
  setData(data) { request.post('/routes/setData').send(data).end((err, res) => { apiActions.apiInitDone(); }) },
};

这里我们使用动作将数据传递给商店。 这是商店。

import Reflux from 'reflux';

import Actions from '../actions/sa.Actions';
import AddonStore from './Addon.Store';
import MixinStoreObject from './Mixin.Store';

function _GotData(data) { this.data1 = data; BasicStore.trigger('data1'); }

let BasicStoreObject = {
  init() { this.listenTo(AddonStore, this.onAddonTrigger); },
  data1: {},
  listenables: Actions,
  mixins: [MixinStoreObject],
  onGotData1: _GotData,
  onAddonTrigger() { BasicStore.trigger('data2'); },
  getData1() { return this.data1; },
  getData2() { return AddonStore.data2; },
  getData3() { return this.data3; }
}
const BasicStore = Reflux.createStore(BasicStoreObject);
export default BasicStore;

请注意,回流允许您在触发器中传递参数。 这是组件。

import React from 'react';

import BasicStore from '../stores/Basic.Store';

let AppCtrlSty = {
  height: '100%',
  padding: '0 10px 0 0'
}

const getState = () => {
  return {
    Data1: BasicStore.getData1(),
    Data2: BasicStore.getData2(),
    Data3: BasicStore.getData3()
  };
};

class AppCtrlRender extends React.Component {
   render() {
    let data1 = JSON.stringify(this.state.Data1, null, 2);
    let data2 = JSON.stringify(this.state.Data2, null, 2);
    let data3 = JSON.stringify(this.state.Data3, null, 2);
    return (
      <div id='AppCtrlSty' style={AppCtrlSty}>
        React 0.14 ReFlux with SuperAgent<br/><br/>
        Data1: {data1}<br/><br/>
        Data2: {data2}<br/><br/>
        Data3: {data3}<br/><br/>
      </div>
    );
  }
}

export default class AppCtrl extends AppCtrlRender {
  constructor() {
    super();
    this.state = getState();
  }

  componentDidMount = () => { this.unsubscribe = BasicStore.listen(this.storeDidChange); }
  componentWillUnmount = () => { this.unsubscribe(); }
  storeDidChange = (id) => {
    switch (id) {
      case 'data1': this.setState({Data1: BasicStore.getData1()}); break;
      case 'data2': this.setState({Data2: BasicStore.getData2()}); break;
      case 'data3': this.setState({Data3: BasicStore.getData3()}); break;
      default: this.setState(getState());
    }
  }
}

我们没有使用mixins。 React类正在弃用mixins,所以现在是不用的好时机。使用额外的商店和api util可能看起来有点过分,但好的做法总是很好的做法。

Map允许使用可选的参数map(function(item){},this)传递它;