arunoda / react-komposer

Feed data into React components by composing containers.
MIT License
733 stars 70 forks source link

Component stuck at "Loading..." #125

Closed mbabauer closed 7 years ago

mbabauer commented 7 years ago

I have a component defined as follows:

import React from 'react';

import Form from 'react-bootstrap/lib/Form';
import FormGroup from 'react-bootstrap/lib/FormGroup';
import FormControl from 'react-bootstrap/lib/FormControl';
import ControlLabel from 'react-bootstrap/lib/ControlLabel';

import Modal from 'react-bootstrap/lib/Modal';

import Col from 'react-bootstrap/lib/Col';
import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';

class JobAddPanel extends React.Component {
  constructor(...args) {
    super(...args);
    this.state = {
      showModal: this.props.showModal,
      open: true,
      jobTitle: '',
      jobStreet1: '',
      jobStreet2: '',
      jobCity: '',
      jobState: '',
      jobZip: ''
    };
  }

  render() {
    const self = this;
    return (
      <div>
        <Modal show={this.state.showModal} onHide={self.close.bind(self)}>
          <Modal.Header closeButton>
            <Modal.Title>Add New Job</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <Form onSubmit={self.save.bind(self)}>
              <FormGroup
                  controlId="jobTitle"
                  validationState={this.getValidationStateTitle()} >
                <ControlLabel>Title</ControlLabel>
                <FormControl
                  type="text"
                  value={self.state.jobTitle}
                  placeholder="Enter Job Title"
                  onChange={self.handleChangeTitle.bind(self)} />
                <FormControl.Feedback />
              </FormGroup>
              <FormGroup
                  controlId="jobStreet1"
                  validationState={this.getValidationStateStreet1()} >
                <ControlLabel>Street</ControlLabel>
                <FormControl
                  type="text"
                  value={self.state.jobStreet1}
                  placeholder="Enter Street"
                  onChange={self.handleChangeStreet1.bind(self)} />
                <FormControl.Feedback />
              </FormGroup>
              <FormGroup
                  controlId="jobStreet2"
                  validationState={this.getValidationStateStreet2()} >
                <ControlLabel>Street 2</ControlLabel>
                <FormControl
                  type="text"
                  value={self.state.jobStreet2}
                  placeholder="Enter Street 2"
                  onChange={self.handleChangeStreet2.bind(self)} />
                <FormControl.Feedback />
              </FormGroup>
              <FormGroup
                  controlId="city"
                  validationState={this.getValidationStateCity()} >
                <ControlLabel>City</ControlLabel>
                <FormControl
                  type="text"
                  value={self.state.city}
                  placeholder="Enter City"
                  onChange={self.handleChangeCity.bind(self)} />
                <FormControl.Feedback />
              </FormGroup>
              <FormGroup
                  controlId="state"
                  validationState={this.getValidationStateState()} >
                <ControlLabel>State</ControlLabel>
                <FormControl
                  type="text"
                  value={self.state.state}
                  placeholder="Enter State"
                  onChange={self.handleChangeState.bind(self)} />
                <FormControl.Feedback />
              </FormGroup>
              <FormGroup
                  controlId="zip"
                  validationState={this.getValidationStateZip()} >
                <ControlLabel>Zip</ControlLabel>
                <FormControl
                  type="text"
                  value={self.state.state}
                  placeholder="Enter Zip"
                  onChange={self.handleChangeZip.bind(self)} />
                <FormControl.Feedback />
              </FormGroup>
            </Form>
          </Modal.Body>
          <Modal.Footer>
            <Button bsStyle="primary" onClick={self.save.bind(self)}>Save</Button>
            <Button onClick={self.close.bind(self)}>Close</Button>
          </Modal.Footer>
        </Modal>
      </div>
    );
  }

  save(event) {
    // Because the test cannot get event argument
      // so call preventDefault() on undefined cause an error
      if (event && event.preventDefault) {
      event.preventDefault();
      }

      const stateVars = this.state;

    this.setState({ showModal: false });
    this.props.createJob(null, stateVars.jobTitle, stateVars.jobStreet1, stateVars.jobStreet2, stateVars.jobCity, stateVars.jobState, stateVars.jobZip);
    this.setState({
      jobTitle: '',
      jobStreet1: '',
      jobStreet2: '',
      jobCity: '',
      jobState: '',
      jobZip: ''
    });
  }

  close(event) {
    this.setState({ showModal: false });
  }
}
import {
    useDeps, composeWithTracker, composeAll
} from 'mantra-core';

import JobAddModal from '../components/job_add_modal.jsx';

export const composer = ({context}, onData) => {
  onData();
};

export const depsMapper = (context, actions) => ({
    createJob: actions.jobs.saveJob,
    clearErrors: actions.jobs.clearErrors,
    context: () => context
});

export default composeAll(
    composeWithTracker(composer),
    useDeps(depsMapper)
)(JobAddModal);

But, when I load said component I get "Loading...". I also tried to call onData() as onData(null, {}), but that throws an error in Tracker. I just need to pass in the actions, no data, to the component.

mbabauer commented 7 years ago

Can anyone help me understand why this component is getting stuck at "Loading..."?

clayne11 commented 7 years ago

You're not passing any data in your composer function.

If you call onData() with no arguments then you put the component into a loading state.

You need to call it like this:

export const composer = ({context}, onData) => {
  // like this if you don't have data
  onData(null {});

  // or like this with data
  const user = Meteor.users.findOne();
  onData(null, {
    user
  });
};
mbabauer commented 7 years ago

Thanks. I should have closed this, but the solution I took was to simply remove the composer method and the call to composeWithTracker(). So, basically all I call is the useDeps() in the composeAll() call, since all I need to do is set the actions for the component.

clayne11 commented 7 years ago

If you're not side-loading data you definitely shouldn't be using react-komposer. If you're simply looking to map some props or add handlers you should look at recompose.

mbabauer commented 7 years ago

For this particular component I only needed to inject some actions (I am using Meteor Mantra). I didn't know how else to make the actions available to the component, to be perfectly honest, and examples are all over the place with how they approach stuff. If you have some better examples I would absolutely love to follow them.

clayne11 commented 7 years ago

I don't use Mantra and I'm not really familiar with it so I can't help you there unfortunately.