skip to Main Content

Currently working on an app this gives users lists of news on a page and on each news has a textbox where you can input your comment.
So for example, 10 news items will have 10 textboxes.

When a user comment after and hit the submit button, the activity indicator appears for all 10 news items, but I want it to only display on where the comment has been made and also after posting the comment, the comment box should be empty

Function

state = {
  posts: [],
  comment: ""
};

commentPost = item => {
  const api = create({
    baseURL: "patch-to-api-url",
    headers: { Accept: "application/json" }
  });
  const self = this;
  self.setState({ modalLoader: true });
  api
    .post("news/posts/" + `${item.id}` + "/comments", {
      media: "",
      text: this.state.comment
    })
    .then(response => {
      console.log(response);
      self.setState({ modalLoader: false });

      //updating the state
      this.setState(prevState => ({
        posts: prevState.posts.map(el => {
          if (el.id === item.id) {
            return {
              ...el,
              commentsCount: el.commentsCount + 1
            };
          }
          return el;
        })
      }));
    });
};

View

<ScrollView>
  {posts.map((item, i) => {
    return (
      <View key={i} style={styles.user}>
        <Card>
          <ListItem
            titleStyle={{ color: "#36c", fontWeight: "500" }}
            onPress={() =>
              navigation.navigate("PostComments", {
                postID: item.id,
                groupID: item.writer.group.id,
                communityID: item.group.community.id
              })
            }
            titleNumberOfLines={2}
            hideChevron={false}
            chevronColor="#36c"
            roundAvatar
            title={item.headline}
            avatar={{
              uri:
                "https://s3.amazonaws.com/uifaces/faces/twitter/brynn/128.jpg"
            }}
          />
          <Text
            style={{
              marginBottom: 10,
              fontSize: 16,
              color: "#000",
              fontFamily: "HelveticaNeue-Light"
            }}
          >
            {item.text}
          </Text>
          <TextInput
            onChangeText={onSetComment}
            label="Write Comment"
            underlineColor="#36a"
            style={{ backgroundColor: "#fff", width: "90%" }}
          />

          <View>
            <Icon
              name="md-send"
              type="ionicon"
              color="#999"
              onPress={() => {
                onCommentPost(item);
              }}
            />

            <View style={styles.loading}>
              <ActivityIndicator animating={modalLoader} size="small" />
            </View>
          </View>
        </Card>
      </View>
    );
  })}
</ScrollView>

2

Answers


  1. You don’t have enough state to accomplish what you want. Wanting an independent spinner in each post implies that you have to store it’s state somewhere.

    You should add the modalLoader attribute to each post and not globally. Change your function to look like this:

    commentPost = item => {
      const api = create({
        baseURL: "patch-to-api-url",
        headers: { Accept: "application/json" }
      });
      const self = this;
      self.setState({ posts: this.state.posts.map(post => post.id === item.id ? {...post, modalLoader: true } : post));
      api
        .post("news/posts/" + `${item.id}` + "/comments", {
          media: "",
          text: this.state.comment
        })
        .then(response => {
          console.log(response);
          self.setState({ posts: this.state.posts.map(post => post.id === item.id ? {...post, modalLoader: false } : post));
    
          //updating the state
          this.setState(prevState => ({
            posts: prevState.posts.map(el => {
              if (el.id === item.id) {
                return {
                  ...el,
                  commentsCount: el.commentsCount + 1
                };
              }
              return el;
            })
          }));
        });
    };
    

    And your component to look like this:

    <ScrollView>
      {posts.map((item, i) => {
        return (
          <View key={i} style={styles.user}>
            <Card>
              <ListItem
                titleStyle={{ color: "#36c", fontWeight: "500" }}
                onPress={() =>
                  navigation.navigate("PostComments", {
                    postID: item.id,
                    groupID: item.writer.group.id,
                    communityID: item.group.community.id
                  })
                }
                titleNumberOfLines={2}
                hideChevron={false}
                chevronColor="#36c"
                roundAvatar
                title={item.headline}
                avatar={{
                  uri:
                    "https://s3.amazonaws.com/uifaces/faces/twitter/brynn/128.jpg"
                }}
              />
              <Text
                style={{
                  marginBottom: 10,
                  fontSize: 16,
                  color: "#000",
                  fontFamily: "HelveticaNeue-Light"
                }}
              >
                {item.text}
              </Text>
              <TextInput
                onChangeText={onSetComment}
                label="Write Comment"
                underlineColor="#36a"
                style={{ backgroundColor: "#fff", width: "90%" }}
              />
    
              <View>
                <Icon
                  name="md-send"
                  type="ionicon"
                  color="#999"
                  onPress={() => {
                    onCommentPost(item);
                  }}
                />
    
                <View style={styles.loading}>
                  <ActivityIndicator animating={item.modalLoader} size="small" />
                </View>
              </View>
            </Card>
          </View>
        );
      })}
    </ScrollView>
    
    Login or Signup to reply.
  2. You are sharing the modalLoader state among all iterated posts. A Post should be a single stateful component. Then for the specific component that was updated you need to update only that state.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search