Ad

ReactJS + Flux: How To Pass Data Attribute From HTML?

- 1 answer

I'm using ReactJS(Flux) and Laravel framework. I need to pass a variable from blade template to React components. I'm trying to use data-x attribute.

My question are..

  1. How can I get the data in React(or Flux architecture)?

  2. Do you have the best practice to store the data in Flux. Is app.js the best place to do it?

Thanks,

index.blade.php

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>ReactJS</title>
  </head>
  <body>
    <section id="react" data-domain="{{env("DOMAIN")}}"></section>
    <script src="{{ elixir('js/bundle.js') }}"></script>
  </body>
</html>

/app.js

var React = require('react');
var SampleApp = require('./components/SampleApp.react');

React.render(
  <SampleApp />,
  document.getElementById('react')
);

/components/SampleApp.react

var React = require('react');
var SampleApp = React.createClass({
  render: function() {
    return (
      <div>
        Hello
      </div>
    );
  }
});
module.exports = SampleApp;

===================================================

Edit 1

I could pass data by using {this.props.domain}. Next step is how to store the data as Flux way.

/app.js

var React = require('react');
var SampleApp = require('./components/SampleApp.react');

var react = document.getElementById('react');

React.render(
  <SampleApp domain={react.dataset.domain}/>,
  react
);

/components/SampleApp.react

var React = require('react');
var SampleApp = React.createClass({
  render: function() {
    return (
      <div>
        Hello {this.props.domain}
      </div>
    );
  }
});
module.exports = SampleApp;

===================================================

Edit 2

Fixed

/index.blade.php
/app.js
/components/SampleApp.react.js
/actions/SampleActionCreators.js
/constans/SampleConstants.js
/dispatcher/SampleAppDispatcher.js
/stores/SampleStore.js

index.blade.php

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>ReactJS</title>
  </head>
  <body>
    <section id="react" data-domain="test.example.com"></section>
    <script src="{{ elixir('js/bundle.js') }}"></script>
  </body>
</html>

/app.js

var React = require('react');
var SampleApp = require('./components/SampleApp.react');

React.render(
  <SampleApp />,
  document.getElementById('react')
);

/components/SampleApp.react.js

var React = require('react');
var SampleActionCreators = require('../actions/SampleActionCreators');
var SampleStore = require('../stores/SampleStore');

function getSampleState() {
  return {
    domain: SampleStore.getDomain()
  };
}

var SampleApp = React.createClass({
  getInitialState: function() {
    return getSampleState();
  },

  componentDidMount: function() {
    SampleStore.addChangeListener(this._onChange);

    var domain = document.querySelector('#react').dataset.domain;
    SampleActionCreators.initData(domain);
  },

  componentWillUnmount: function() {
    SampleStore.removeChangeListener(this._onChange);
  },

  render: function() {
    return (
      <div>
        Hello {this.state.domain}
      </div>
    );
  },

  _onChange: function() {
    this.setState(getSampleState());
  }

});
module.exports = SampleApp;

/actions/SampleActionCreators.js

var SampleAppDispatcher = require('../dispatcher/SampleAppDispatcher');
var SampleConstants = require('../constants/SampleConstants');

var ActionTypes = SampleConstants.ActionTypes;

module.exports = {

    initData: function(domain) {
        SampleAppDispatcher.dispatch({
            type: ActionTypes.SAMPLE_INIT_DATA,
            domain: domain
        });
    },

};

/constans/SampleConstants.js

var keyMirror = require('keymirror');

module.exports = keyMirror({
  ActionTypes: keyMirror({
    SAMPLE_INIT_DATA: null
  })
});

/dispatcher/SampleAppDispatcher.js

var Dispatcher = require('flux').Dispatcher;

module.exports = new Dispatcher();

/stores/SampleStore.js

var SampleAppDispatcher = require('../dispatcher/SampleAppDispatcher');
var SampleConstants = require('../constants/SampleConstants');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');

var CHANGE_EVENT = "change";

var _domain = "";

var SampleStore = assign({}, EventEmitter.prototype, {

    getDomain: function() {
        return _domain;
    },

    emitChange: function() {
        this.emit(CHANGE_EVENT);
    },

    addChangeListener: function(callback) {
        this.on(CHANGE_EVENT, callback);
    },

    removeChangeListener: function(callback) {
        this.removeListener(CHANGE_EVENT, callback);
    }
});

SampleAppDispatcher.register(function(action) {

    switch (action.actionType) {
        case SampleConstants.SAMPLE_INIT_DATA:
            _domain = action.domain;
            SampleStore.emitChange();
            break;

        default:
            // no op
    }
});

module.exports = SampleStore;
Ad

Answer

Your second edit is "correct" Flux way, same one I used on several large scale projects.

More simpler, alternative approach would be to get domain in app.js and pass it to your SampleApp as prop. This requires for DOM from your blade template to be loaded before JS executes. Since you are already putting your JS on bottom you should be good but I added window.onload event just to make it sure.

var React = require('react');
var SampleApp = require('./components/SampleApp.react');

function getDomain() {
    return document.getElementById('react').dataset.domain;
}

function initReact() {

    var params = {
        domain: getDomain()
    };

    React.render(
        <SampleApp {...params} />,
        document.getElementById('react')
    );

}

window.onload = function() {
    initReact();
};

Now you can use {this.props.domain} to access your domain value in SampleApp.reatc.js

Ad
source: stackoverflow.com
Ad