mpen mpen - 4 years ago 183
React JSX Question

How can a component send a message to its sibling without moving the state up the component tree?

I've got a "page" component which houses a form and a list. The form and the list are completely self-contained and disjoint except for the fact that when you save the form, the list should refresh.

My page component looks like this, in its entirety:

export default class PaymentsPage extends React.PureComponent {

static propTypes = {
bookingId: XPropTypes.stringOrNumber.isRequired,
test: PropTypes.bool,
stripePublishableKey: PropTypes.string,
stripeUserId: PropTypes.string,
};

render() {
return (
<div>
<ContentSection title="Enter Payment" storageKey="record-payment">
<RecordPaymentForm bookingId={this.props.bookingId} test={this.props.test} />
</ContentSection>
<ContentSection title="Previous Payments" storageKey="previous-payments">
<PreviousPaymentsTable bookingId={this.props.bookingId} test={this.props.test} stripePublishableKey={this.props.stripePublishableKey} stripeUserId={this.props.stripeUserId} />
</ContentSection>
</div>
)
}
}


My question is, how can
RecordPaymentForm
send a message to
PreviousPaymentsTable
to tell it to refresh?

I don't want to move
RecordPaymentForm
's state up into
PaymentsPage
because I want it to remain self-contained.

I'm not using flux/redux, nor do I plan on it right now.

Answer Source

Using mufa (event oriented programming), communication among siblings will be as following :

Component Sender (Publisher) :

import {fire} from 'mufa';

class RecordPaymentForm extends React.Component {

     // Assuming that the trigger to send the message is the following
     handleClick() {
       const message = 'this is a message from RecordPaymentForm';
       fire('sendSomething', message); 
     }
}

Component Receiver (Subscriber) :

import {on} from 'mufa';

class PreviousPaymentsTable extends React.Component {

    componentDidMount() {
      on('sendSomething', (message) => {
         this.setState({recordPaymenetMessage: message});
      })
    }
}

//if your are using npm => import {on, fire} from 'mufa';
const {on, fire} = window.mufa; 

class RecordPaymentForm extends React.Component {


     onClick(event) {
       fire('addPayment', this.refs.item.value, this.refs.price.value); 
     }
     
     render() {
       return (
          <div>
            <input ref="item" placeholder="item name" /> 
            <input ref="price" placeholder="price" type="number" />
            <button onClick={this.onClick.bind(this)}>Add</button>
          </div>
          )
     }
}



class PreviousPaymentsTable extends React.Component {
  
    state={records:[]}
    componentDidMount() {
      on('addPayment', (item, price) => {
         this.setState({records: [...this.state.records, {item, price}]});
      })
    }

   
   render() {
    
      return (
        <ul>
          {
            this.state.records.map((r, index) => 
              <li key={index}> <b> {r.item} : </b> {r.price} $ </li>)
          }
        </ul>
      ) 
    }
}


class App extends React.Component {


  render() {
  
    return (
      <div>
         <RecordPaymentForm />
         <PreviousPaymentsTable />
      </div>
    )
  }
}

ReactDOM.render(<App />, document.querySelector('section'))
<script src="https://cdn.rawgit.com/abdennour/mufa/ddf78fd9/cdn/mufa-latest.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<section />

General Rules for React with Event-driven :

  1. publish (fire) : is called in events handlers.

  2. subscribe (on) : is called in componentDidMount.

  3. unsubscribe (off) : is called in componentWillUnmount

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