Nan
Nan

Reputation: 25

Meteor method call in React Native not reactive

I am current developing react native with meteor backend,

I have a subscription in createContainer, and the subscription contains userId, which I will use a meteor method to fetch the user picture as the code below, but I cant make it work, the user picture uri never gets to the component...

could anyone help me with it? what do you guys think is the best practice when it comes to async data handling for react native& meteor?

thank you very much!!!

  getAvatar(buyerId){
    Meteor.call('getUserPicture', buyerId, (err, res)=>{
       if(err){
         console.log(err);
         return err;
       }
       else{
         console.log(res);
         return res;
       }
     })
  }

  render() {
    if(this.props.handle.ready()){
      return (
        <View>
        <ScrollView >
        <List containerStyle={{marginBottom: 20}}>
        {
          this.props.priceDiscussesSelling && this.props.priceDiscussesSelling.map((priceDiscuss, i) => {

            return (<ListItem
              roundAvatar
              avatar={{uri: this.getAvatar(priceDiscuss.buyerId)&&this.getAvatar(priceDiscuss.buyerId)}}
              key={i}
              subtitle={priceDiscuss.lastDiscussItem.createdAt}
              rightTitle={priceDiscuss.status}
              title={priceDiscuss.lastDiscussItem.content}
              onPress={()=>{this.props.navigation.navigate('PriceDiscussDetail', {priceDiscussId: priceDiscuss._id})}}
              />)
            }
          )
        }
        </List>

        </ScrollView>

        </View>
      );
    }
    }

export default createContainer(param => {
    let handle = Meteor.subscribe('getPersonalSellingPriceDiscusses',(err)=>{
      if(err){
        console.log(err);
      }
      else{
      }
    });
    return {
      priceDiscussesSelling: Meteor.collection('priceDiscusses').find({ sellerId : Meteor.userId()}),
      handle: handle
    }
  }, PriceDiscussSelling);

Upvotes: 0

Views: 351

Answers (1)

Spencer Carli
Spencer Carli

Reputation: 696

I would say that this is a good case for using component state. Also, it's a good idea to avoid making remote requests from the render method because it, as it stands, will be called each time the component re-renders.

To make the request I would modify the getAvatar function to it writes the result to state.

getAvatar(buyerId){
  Meteor.call('getUserPicture', buyerId, (err, res)=>{
    if(err){
      console.log(err);
      return err;
    }
    else{
      console.log(res);
      const updatedState = {};
      updatedState[buyerId] = res; // there may be a more succinct way of doing this
      this.setState({
        ...this.state, // ensure current state gets copied
        ...updatedState,
      });
    }
  })
}

then from within the component you can render the result of the method call, which is stored in state

render() {
  if(this.props.handle.ready()){
    return (
      <View>
      <ScrollView >
      <List containerStyle={{marginBottom: 20}}>
      {
        this.props.priceDiscussesSelling && this.props.priceDiscussesSelling.map((priceDiscuss, i) => {

          return (<ListItem
            roundAvatar
            avatar={this.state[priceDiscuss.buyerId] ? {uri: this.state[priceDiscuss.buyerId]} : null}
            key={i}
            subtitle={priceDiscuss.lastDiscussItem.createdAt}
            rightTitle={priceDiscuss.status}
            title={priceDiscuss.lastDiscussItem.content}
            onPress={()=>{this.props.navigation.navigate('PriceDiscussDetail', {priceDiscussId: priceDiscuss._id})}}
            />)
          }
        )
      }
      </List>

      </ScrollView>

      </View>
    );
  }
}

And finally you can make the requests for data from componentDidMount, componentWillReceiveProps or some other life cycle method (only when you need to - so check that the state/props have change).

componentWillReceiveProps(nextProps) {
  if (this.props.priceDiscussesSelling.length !== nextProps.priceDiscussesSelling.length) {
    nextProps.priceDiscussesSelling.forEach((priceDiscuss) => {
      this.getAvatar(priceDiscuss.buyerId);
    });
  }
}

Upvotes: 1

Related Questions