EliaMelfior EliaMelfior - 1 year ago 65
Javascript Question

Dynamic requires in React

Edit: I created wrappers for each different component, required the necessary collections and passed them as props to a main, generic component.

We made 3 very similar components using React, and ended up having three really similar files with some minor modifications, depending on the specific component.

My question is really simple (but might be hard to implement), we want to utilize the same file for that base, so i want to dynamically use requires, and initialize variables, how can i do it?

var ProtocolSelectedCollection = require("../collections/ProtocolSelectedCollection");
var selectedCollection = new ProtocolSelectedCollection();
var baseURL = Utils.getSystemUrl();

easyGrid({
gridName: "protocolSelectedCollection"
});


In the code above, for example, i would like to require a different file from /collections/, depending on the component, and i would also like to name the gridName differently.

So, how can i do it? I will post more code if necessary or clear any doubts about it.

So here is the full component, it's really small.

var React = require('react');

const Utils = require("Utils");

var RowCt = require("reactor/src/FlexGrid/components/Layout/Row/Row");
var Col = require("reactor/src/FlexGrid/components/Layout/Col.jsx");
var Row = require("reactor/src/FlexGrid/components/Layout/Row/RowPresentation.jsx");
var Box = require("reactor/src/FlexGrid/components/Layout/Box.jsx");
var ContentLabel = require("reactor/src/Atomic/components/Mols/ContentLabel.jsx");
var AsyncLoading = require("reactor/src/Atomic/components/Helpers/AsyncLoading/AsyncLoading");
var Store = require("reactor/src/store/store");
var Provider = require("react-redux").Provider;
var FormControl = require('reactor/src/Form/components/Atoms/FormControl/FormControl');
var FormGroup = require("reactor/src/Form/components/Mols/FormGroup");
var InputAddon = require("reactor/src/Form/components/Atoms/InputAddon");
var InputGroup = require("reactor/src/Form/components/Mols/InputGroup/InputGroup.jsx");
var easyGrid = require("reactor/src/FlexGrid/components/Helpers/EasyGrid");
var when = require("when");

var ProtocolSelectedCollection = require("../collections/ProtocolSelectedCollection");
var selectedCollection = new ProtocolSelectedCollection();
var baseURL = Utils.getSystemUrl();

easyGrid({
gridName: "protocolSelectedCollection"
});

var cursorPointer = {
cursor: 'pointer'
};

var rowWrapper = {
borderWidth: '0px 0px 1px',
borderStyle: 'solid',
borderColor: 'rgb(204, 204, 204)',
marginBottom: '10px',
cursor: 'pointer'
};


require("./ProtocolAuthorizedWidget.css");
require("reactorCmps/tokens/general");

module.exports = React.createClass({
componentDidMount() {
var me = this;

return me.loadData();
},

filterValue: "",

loadData() {
var me = this;

return me.refs.async.getWrappedInstance().loadData(true);
},

getChildren(data) {
var me = this, protocolsData = Array.isArray(data) ? data : [], protocols = [];

if (!protocolsData.length) {
return (
<span>{SE.t(103092)}</span>
);
}

protocolsData.map(function(element, i) {
protocols.push(
<div style={rowWrapper}
key={i}
onMouseLeave={me.setRowState.bind(me, element.cdproctype, 'leave')}
onMouseOver={me.setRowState.bind(me, element.cdproctype, 'over')}
onClick={me.startProtocol.bind(me, element.cdproctype)}
title={SE.t(104859)}>

<RowCt
oid={element.cdproctype}
selectType={0}
multireducerKey={"protocolSelectedCollection"}>

<Col xs sm md lg>
<Row nested>
<Col xs={1} sm={1} md={1} lg={1} >
<div ref={"protocol" + element.cdproctype}></div>
<img ref={"protocolImage" + element.cdproctype}
src={baseURL + "/common/images/type_icons/64x64/" + element.fgicon + ".png"}
className="rowImage" />
</Col>
<Col xs={11} sm={11} md={11} lg={11}>
<Box>
<ContentLabel title={element.idproctype} text={element.nmtitle}></ContentLabel>
</Box>
</Col>
</Row>
</Col>
</RowCt>
</div>

);
});

return (
<div>
<div>
{protocols}
</div>
</div>
);
},

startProtocol(cdproctype) {
var url = baseURL + "/document/dc_protocol/protocol_data.php?caption=&action=1&cdproctype=" + cdproctype;
var width = 700;
var height = 515;

Utils.openPopUp(url, width, height);
},

setRowState(cdproctype, event) {
var me = this;

if (event === 'over') {
$(me.refs.async.getWrappedInstance().refs['protocolImage' + cdproctype]).hide();
$(me.refs.async.getWrappedInstance().refs['protocol' + cdproctype]).addClass("se-valign btn btn-success seicon-play playButton rowImage");
} else if (event === 'leave') {
$(me.refs.async.getWrappedInstance().refs['protocolImage' + cdproctype]).show();
$(me.refs.async.getWrappedInstance().refs['protocol' + cdproctype]).removeClass();
}
},

filterProtocol(e) {
var me = this;
var enterKeyCode = 13;

if (e.target) {
me.filterValue = e.target.value;
}

if (e.nativeEvent.keyCode === enterKeyCode) {
me.loadData();
}
},

getData() {
var me = this, deferred = when.defer();
var oid = me.props.CardOid;
var searchTerm = me.filterValue;

selectedCollection.fetch({oid: oid, searchTerm: searchTerm}).then(function(results) {
deferred.resolve(results);
});

return deferred.promise;
},

render() {
var me = this, searchFilter;

searchFilter = (
<div>
<div>
<FormGroup>
<InputGroup>
<InputAddon
onClick={me.loadData}
style={cursorPointer}
className="seicon-search"
title={SE.t(214653)}
>

</InputAddon>
<div>
<FormControl
onKeyPress={me.filterProtocol}
/>
</div>
</InputGroup>
</FormGroup>
</div>
</div>
);

return (
<div>
<div>
{searchFilter}
</div>

<Provider store={Store} withRef>
<AsyncLoading
ref="async"
oid={"protocolSelectedCollection" + me.props.CardOid}
fireLoad
loadFn={me.getData}
getChildren={me.getChildren}
/>
</Provider>

</div>
);
}

});

Answer Source

If your components are really similar,you can create one single component which does some actions and renders some result based on props.

Just pass some props. And inside of your component, do your actions like you do in those 3 component separately. Here, i tried to demonstrate how to use props to render different results from same component:

class MixedComponent extends React.Component {
  constructor(props) { 
    super(props)
    this.state = {type: ''}
  }

  componentDidMount() {
    if (this.props.prop1) // if prop1 exists
      this.setState({type: 'do something'})
    else 
      this.setState({type: 'Something else'})
  }

  render() {
    let result;
    if (this.props.prop1) {
      result = (
        <div>
          Render this component based on <strong>{this.props.prop1}</strong>
          <p>Type -> {this.state.type}</p>
        </div>
      )
    } else if (this.props.prop2) {
      result = (
        <div>
          Render this component based on <strong>{this.props.prop2}</strong>
          <p>Type -> {this.state.type}</p>
        </div>
      )
    }
    else if (this.props.prop3) {
      result = (
        <div>
          Render this component based on <strong>{this.props.prop3}</strong>
          <p>Type -> {this.state.type}</p>
        </div>
      )
    }
    return result
  }
}

And use this component with different props in your main component:

class Main extends React.Component {
  render() {
    return (
      <div>
        <h4>Render different results based on props with same component!</h4>
        <hr/>
        <MixedComponent prop1="Hello,"/>
        <MixedComponent prop2="Dear"/>
        <MixedComponent prop3="World!"/>
      </div>
     )
  }
}

This is just a demonstration of using props. You can derive the idea from here. Here is a working example on codepen:

https://codepen.io/anon/pen/dREqZK?editors=1010

You can play with it.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download