0

I'm still a bit starting up on react and I've now used my 2nd solution (here) to show/hide components.

My problem now is if I have multiple child elements and I need to open another component (Preference) (this I managed already, and clicking outside or other place hides it) but at the same time I need to pass information to that other component. I have attached my small demo of it. My question again is how do I pass from Child/Child2 components say it's _preferences or it's coordinates to the Preferences component?

edit: added jsfiddle link.

the whole code snippet:

<html>
  <body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.7.0/lodash.min.js"></script>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.1/react-with-addons.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.1/JSXTransformer.js"></script>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>

    <div id="render-here"></div>

    <script type="text/jsx">
      var Parent = React.createClass({
        getInitialState: function () {
          return { 
            showPreference: false,
            childComponents: 0
          };
        },
        shouldComponentUpdate: function() {
          console.log('parent should update');
          return true;
        },
        _click: function() {
          this.setState({childComponents: this.state.childComponents + 1});
        },
        _showPreference: function() {
          this.setState({showPreference: true})
        },
        _hidePreference: function() {
          this.setState({showPreference: false})
        },
        render: function() {
          var childComponents = [];

          _.times(this.state.childComponents, function(n) {
            if (n % 2)
              childComponents.push(<Child key={'foobar'+n} showPreference={this._showPreference} />)
            else
              childComponents.push(<Child2 key={'foobar'+n} showPreference={this._showPreference} />)
          }.bind(this));

          return(
            <div style={{height:'100%', width:'100%', border:'1px solid blue'}} onClick={this._hidePreference}>
              {this.state.showPreference ? <Preference /> : null}
              <div onClick={this._click}>Add components</div>
              {childComponents}
            </div>
          )
        }
      });

      var Preference = React.createClass({
        shouldComponentUpdate: function() {
          console.log('preference should update');
          return true;
        },
        _click: function(e) {
          e.stopPropagation();
        },
        render: function() {
          return(
            <div ref="pref" style={{position:'absolute', left: '250px'}} onClick={this._click}>
              <div>Some preferences here...</div>
            </div>
          )
        }
      });

      var Child = React.createClass({
        shouldComponentUpdate: function() {
          console.log('child should update');
          return true;
        },
        _preferences: ['child', 'preferences'],
        _click: function(e) {
          e.stopPropagation();
          this.props.showPreference();
        },
        render: function() {
          return(
            <div ref="me" onClick={this._click}>Child - click me for preference</div>
          )
        }
      });

      var Child2 = React.createClass({
        shouldComponentUpdate: function() {
          console.log('child should update');
          return true;
        },
        _preferences: ['child2', 'preferences'],
        _click: function(e) {
          e.stopPropagation();
          this.props.showPreference();
        },
        render: function() {
          return(
            <div ref="me" onClick={this._click}>Child 2 - click me for preference</div>
          )
        }
      });

      React.render(<Parent name="foobar" />, document.getElementById('render-here'));
    </script>
  </body>
</html>

jsfiddle link.

Community
  • 1
  • 1
index
  • 3,697
  • 7
  • 36
  • 55

1 Answers1

0

First off, never store arbitrary objects in your React components, like you do with _preferences: ['child', 'preferences']. Any data in a component should be inside the state of that component, or be passed as props to it.

If you put an array like that on the component object, it will be shared between all instances of that component. If you only ever have one instance of it, you probably won't notice it. But it will probably bite you as soon as you need more than that. And by using state and setState to mutate it, React knows when to re-render your component.

Now to your question; your Parent component should probably be the component that holds the preferences object in it's state. The Parent component then passes it to the Child, Child2 and Preference components as props. If Child, Child2 or Preference wants to modify that object, Parent would pass a callback as a prop to them, which they can call to tell Parent that it should be changed. Something like:

let React = require('react');

let Parent = React.createClass({
  getInitialState() {
    return {
      preferences: {
        someKey: 'someValue'
      }
    };
  },
  changePreference(pref) {
    this.setState(state => {
      state.preferences[pref.name] = pref.value;
      return state;
    });
  },
  render() {
    return (
      <div>
        <Child 
          preferences={this.state.preferences} 
          onChangePreference={pref => this.changePreference(pref)} 
        />
        <Preference 
          preferences={this.state.preferences} 
          onChangePreference={pref => this.changePreference(pref)} 
        />
      </div>
    );
  }
});
Anders Ekdahl
  • 22,685
  • 4
  • 70
  • 59
  • Hi. Still reading your answer, but what are `=>` in javascript? Your syntax is a bit different from mine. – index Apr 29 '15 at 02:06
  • I've used some upcoming features in Javascript in the code. It's quite common for React projects to use a compiler like Babel to compile ES6 code into ES5 code, which lets you use new features today, without having to wait for browsers to implement them. This: `let func = pref => this.changePreference(pref)` is what's called an arrow function. Its ES5 equivalent is `var that = this; var func = function(pref) { return that.changePreference(pref); }`. – Anders Ekdahl Apr 29 '15 at 05:32