How to pass create container props into the class states in meteor with react


#1

hello every one i have product form to update product information, i called perticular product’s data from create container in meteor and passed that props inside class component which is a form to update information.

  import React, { Component } from 'react';
  import {ProductMasterApi} from '../../api/productMaster';
  import { createContainer } from 'meteor/react-meteor-data';

  class Example extends Component {
  constructor(props) {
   super(props);
    this.state = {
     name:props.name,
     price:props.price,
    };
  }
  setValue(field, event) {
let object = {};
object[field] = event.target.value;
this.setState(object);
}

  render() {
    return (
    <div>
    <form>
    <label htmlFor="username" className="input-label">Name</label>
    <input type="text" className="form-control" placeholder="" required value={this.state.name}  onChange={this.setValue.bind(this, 'name')} />
    <label htmlFor="username" className="input-label">price</label>
    <input type="number" className="form-control" placeholder="" required value={this.state.price}  onChange={this.setValue.bind(this, 'price')} />

    </form>
    </div>
  );
}

}

  export default createContainer((props) => {
  const handle = Meteor.subscribe("productMasterbyindividual",props.match.params.id);
  return {
      loading: !handle.ready(),
      product : handle.ready() ? ProductMasterApi.find({_id:props.match.params.id}).fetch() : null,
  };
}, Example);

Now what happens is that when it renders firs time then product props is null which sets into the state and second time when the actual details comes from database then we cant set state in constructor because it run only first time in rendering


#2

Seting a component’s internal state with props is considered an anti pattern and discouraged because of reasons similar to what you’ve come to realize in your case.

What happens is, your component is mounted right before the first time it gets rendered with null values provided by createContainer and subsequent changes provided to the props by createContainer come in from reactive data source updates and do not cause a remounts, merely rerenders at which point, the constructor had its first and only invocation.

If you really set your mind to updating the state with prop changes, then I guess you can use the componentWillReceiveProps(nextProps) lifecycle hook. Make sure to read that section of the docs for caveats, though.


#3

i guess there is no other solution instead using componentWillReceiveProps(nextProps) if there is any oother solution to update products or any other way or method then let me know, because ultimately i have to fetch data from container and set it to the class states


#4

Well, what you’re trying to do and your logic is subjective because it changes the UX.

For instance, within your designed UX, if a form is initialized with (the second render with data) for values that set the state and while the user is changing the values, some other value comes in from the database, user’s values will have been overwritten.

If it were my decision, I would keep separate track of the incoming props, utilizing subscription handle readiness for presenting the initial values, and keep track of the state, also utilize component’s lifecycle methods to keep track of whether or not inputs have been updated with different values and provide the user with information about the external changes as well has what they have been changing.


#5

thanks , here what i did , i wrap the whole component and passed into its parent component like this…

React, { Component } from 'react';
import {ProductMasterApi} from '../../api/productMaster';
import { createContainer } from 'meteor/react-meteor-data';
import { SubCategoryApi } from '../../api/subCategory';
import { CategoryApi } from '../../api/category';
import Example from './Example';

class ExampleContainer  extends Component {

 render(){
return(
  <div>
  {
    this.props.product == null ? null :<Example product={this.props.product} categories={this.props.categories} 
subcategories={this.props.subcategories}/>
  }
  </div>
);
}
}
export default createContainer((props) => {
const handle = Meteor.subscribe('subCategory');
const handle1 = Meteor.subscribe('category');
const handle2 = Meteor.subscribe("productMasterbyindividual",props.match.params.id);
return {
    loading: !handle2.ready(),
    subcategories: SubCategoryApi.find({}).fetch(),
    categories: CategoryApi.find({}).fetch(),
    product : handle2.ready() ? ProductMasterApi.find({_id:props.match.params.id}).fetch() : null,
};
} , ExampleContainer);

now its working fine thank you very much


#6

is this a right way to do it, or i need to improve my programming skills?


#7

Come on now, don’t be hard on yourself. There are multiple ways of solving a problem, and f your solution works and it works the way you want it to work, than all’s good. :wink:


#8

yes you are totally right thanks for your suggestions and advices