简体   繁体   English

ReactJS和反流的一般状态问题

[英]General State Questions with ReactJS & Reflux

I'm pretty new to React and am trying to wrap my mind around Reflux. 我对React还是很陌生,正在尝试将自己的想法围绕Reflux。

Here's my scenario: 这是我的情况:

I currently have a very simple app that is calling some song data from a rest api, once retrieved, it is being stored in state.songs (this is happening within an Init function in the song store): 我目前有一个非常简单的应用程序,该应用程序从rest 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??
  }

 });

Here's the component that's rendering the song data: 这是呈现歌曲数据的组件:

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>
  );
 }
});

This is all working as intended. 这一切都按预期进行。

I also have a list of albums, which is rendered in it's own component (and has it's own store), and i'm trying to hook up a click function on an album item, so once an album title is clicked, this.state.songs is filtered and the songs component is re-rendered. 我也有一个专辑列表,该列表以其自己的组件呈现(并拥有自己的商店),并且我试图连接一个专辑项目上的点击功能,因此一旦点击了专辑标题,this.state .songs被过滤,并且歌曲组件被重新渲染。

The issue i'm having is when I try to access this.state.songs from the song store, it's undefined (see onHandleClick func in song store above). 我遇到的问题是,当我尝试从歌曲存储库访问this.state.songs时,它是未定义的(请参见上面的歌曲存储库中的onHandleClick函数)。

Album list component: 专辑列表组件:

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>
    );
  }
});

Album list store: 专辑列表存储:

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();
  }
});

Can anyone help me out? 谁能帮我吗? An answer with some explaining would be awesome so I can understand what the problem is. 一个带有一些解释的答案将是很棒的,所以我可以知道问题是什么。

Thanks! 谢谢!

You should be using actions for handleClick or any other call from the component to the store. 您应该对handleClick或从组件到商店的任何其他调用使用操作。 I would also suggest separating your api calls from the store. 我还建议将您的api调用与商店分开。 Here is an example from https://github.com/calitek/ReactPatterns React.14/ReFluxSuperAgent. 这是来自https://github.com/calitek/ReactPatterns React.14 / ReFluxSuperAgent的示例。

app.js 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') ); 

Note the action and api.store import. 注意操作和api.store导入。 Here is 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 is doing a setData here but it could be the initial get calls. apiInit在这里执行setData,但它可能是最初的get调用。 Here it the api. 这里是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(); }) }, }; 

Here we use actions to pass the data to the store. 在这里,我们使用操作将数据传递到商店。 Here is the store. 这是商店。

 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; 

Note that reflux allows you to pass parameters in trigger. 请注意,回流允许您在触发器中传递参数。 Here is the component. 这是组件。

 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()); } } } 

We are not using mixins. 我们没有使用mixin。 React classes are deprecating mixins so now is a good time to do without. React类不赞成使用mixins,所以现在是一个很好的时机。 It may seen like overkill to use an extra store and api util but good practices are always good practice. 使用额外的存储区和api util可能看起来有些矫kill过正,但好的做法始终是好的做法。

Map allows passing this with an optional parameter map(function(item){}, this); Map允许通过可选参数map(function(item){},this)传递此参数;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM