React-Native Comments组件

时间:2018-08-06 03:59:09

标签: javascript reactjs performance user-interface react-native

我希望我的用户能够针对某个主题发表评论,并能够回复评论。

我的想法是,每个主要评论都有一个包含子评论的单位列表。首先,我从屏幕上加载所有主要评论,然后每个主要评论加载其子评论,并将它们放入其 FlatList 。每个commentItem都有一个TextInput,用于设置状态。

问题是,如果一个主题的评论超过30条,屏幕将变得非常缓慢且缓慢。同样在主注释的TextInput中键入回复非常延迟。因为必须重新渲染所有内容。.很明显.setState()引起了问题。

有人知道如何构造和加载组件而不会遇到任何性能问题吗?

MainCommentItem

class CommentItem extends Component {
  constructor(props) {
    super(props);

    this.state = {
      user_fullName: "",
      user_profileImgUrl: false,
      sub_comments: null
    };

    this.renderSubComment = this.renderSubComment.bind(this);

    this.loadUserData();
    this.loadSubComments();
  }

  loadSubComments() {
    firebase
      .database()
      .ref("Comments")
      .child(this.props.comment.taskID)
      .orderByChild("parentID")
      .equalTo(this.props.comment.commentID)
      .on("value", snap => {
        if (snap.exists()) {
          var comments = [];
          snap.forEach(comment => {
            comments.push(comment.val());
          });
          this.setState({
            sub_comments: comments
          });
        }
      });
  }

  loadUserData() {
    var commentUserRef = firebase
      .database()
      .ref("Users")
      .child(this.props.comment.posterID);
    commentUserRef.once("value", snap => {
      if (snap.exists()) {
        try {
          this.setState({
            user_profileImgUrl: { uri: snap.toJSON().profileImgUrl },
            user_fullName:
              snap.toJSON().firstName +
              " " +
              snap.toJSON().lastName.charAt(0) +
              "."
          });
        } catch (error) {
          alert(error);
        }
      }
    });
  }

  sendComment() {
    if (this.state.comment_desc === "") return;

    var commentID = firebase
      .database()
      .ref("Comments")
      .child(this.props.comment.taskID)
      .push().key;

    var new_comment = {
      posterID: firebase.auth().currentUser.uid,
      desc: this.state.comment_desc,
      date: moment().unix(),
      parentID: this.props.comment.commentID,
      commentID: commentID,
      taskID: this.props.comment.taskID
    };

    this.setState({ comment_desc: "" });

    firebase
      .database()
      .ref("Comments")
      .child(this.props.comment.taskID)
      .child(commentID)
      .set(new_comment);
  }

  renderSubComment(comment) {
    return <CommentItemSub comment={comment} />;
    //return <Text>asdf</Text>;
  }

  render() {
    return (
      <View style={styles.offerContainer}>
        <View style={styles.offerItemHolder}>
          <View row>
            <View>
              <Text
                style={{
                  fontSize: 15,
                  fontFamily: Globals.font_primary,
                  color: Globals.color_primary
                }}
              >
                {this.state.user_fullName}:{" "}
              </Text>
              {this.state.user_profileImgUrl ? (
                <FastImage
                  style={{
                    width: 30,
                    height: 30,
                    borderRadius: 15,
                    alignSelf: "center",
                    marginTop: 5,
                    marginBottom: 10
                  }}
                  source={this.state.user_profileImgUrl}
                />
              ) : (
                <View style={{ width: 60, height: 60 }} />
              )}
            </View>
            <View spread>
              <Text
                style={{
                  fontFamily: Globals.font_primary,
                  marginTop: 1.5,
                  marginRight: 5,
                  width: 230
                }}
              >
                {this.props.comment.desc}
              </Text>
            </View>
          </View>
          <View row>
            <View style={{ flex: 1 }}>
              <TextInput
                ref={r => {
                  this._textInputRef = r;
                }}
                multiline={true}
                style={{
                  fontFamily: Globals.font_primary,
                  fontSize: 15,
                  backgroundColor: "white",
                  marginBottom: 2,
                  marginLeft: 2,
                  marginTop: 2,
                  marginRight: 2,
                  borderRadius: 5,
                  //ios
                  shadowOpacity: 0.15,
                  shadowRadius: 6,
                  shadowOffset: {
                    height: 2,
                    width: 1
                  },
                  //android
                  elevation: 2.5
                }}
                placeholder=" Auf Frage antworten.."
                keyboardType="default"
                hideUnderline={true}
                value={this.state.comment_desc}
                onChangeText={desc => this.setState({ comment_desc: desc })}
              />
            </View>
            <TouchableOpacity onPress={() => this.sendComment()}>
              <FastImage
                style={{
                  width: 22,
                  height: 22,
                  marginLeft: 10,
                  marginRight: 10,
                  marginTop: 5
                }}
                source={Globals.icon_send}
              />
            </TouchableOpacity>
          </View>
          <FlatList
            initialNumToRender={5}
            style={{ marginLeft: 30 }}
            data={this.state.sub_comments}
            keyExtractor={comment => comment.commentID}
            scrollEnabled={false}
            renderItem={({ item: comment }) => this.renderSubComment(comment)}
          />
        </View>
      </View>
    );
  }
}

var styles = StyleSheet.create({
  offerItemHolder: {},
  offerContainer: {
    marginTop: 5,
    marginBottom: 5,
    marginLeft: 2,
    marginRight: 2
  }
});

module.exports = CommentItem;

SubCommentItem

class CommentItemSub extends Component {
  constructor(props) {
    super(props);

    this.state = {
      user_fullName: "",
      user_profileImgUrl: false,
      sub_comments: null
    };

    this.loadUserData();
  }

  loadUserData() {
    var commentUserRef = firebase
      .database()
      .ref("Users")
      .child(this.props.comment.posterID);
    commentUserRef.once("value", snap => {
      if (snap.exists()) {
        try {
          this.setState({
            user_profileImgUrl: { uri: snap.toJSON().profileImgUrl },
            user_fullName:
              snap.toJSON().firstName +
              " " +
              snap.toJSON().lastName.charAt(0) +
              "."
          });
        } catch (error) {
          alert(error);
        }
      }
    });
  }

  sendComment() {
    if (this.state.comment_desc === "") return;

    var commentID = firebase
      .database()
      .ref("Comments")
      .child(this.props.comment.taskID)
      .push().key;

    var new_comment = {
      posterID: firebase.auth().currentUser.uid,
      desc: this.state.comment_desc,
      date: moment().unix(),
      parentID: this.props.comment.parentID,
      commentID: commentID,
      taskID: this.props.comment.taskID
    };

    this.setState({ comment_desc: "" });

    this.state.comment_desc;
    firebase
      .database()
      .ref("Comments")
      .child(this.props.comment.taskID)
      .child(commentID)
      .set(new_comment);
  }

  render() {
    return (
      <View style={styles.offerContainer}>
        <View style={styles.offerItemHolder}>
          <View row>
            <View>
              <Text
                style={{
                  fontSize: 15,
                  fontFamily: Globals.font_primary,
                  color: Globals.color_primary
                }}
              >
                {this.state.user_fullName}:{" "}
              </Text>
              {this.state.user_profileImgUrl ? (
                <FastImage
                  style={{
                    width: 30,
                    height: 30,
                    borderRadius: 15,
                    alignSelf: "center",
                    marginTop: 5,
                    marginBottom: 10
                  }}
                  source={this.state.user_profileImgUrl}
                />
              ) : (
                <View style={{ width: 60, height: 60 }} />
              )}
            </View>
            <View spread>
              <Text
                style={{
                  fontFamily: Globals.font_primary,
                  marginTop: 1.5,
                  marginRight: 5,
                  width: 230
                }}
              >
                {this.props.comment.desc}
              </Text>
            </View>
          </View>
          <View row>
            <View style={{ flex: 1 }}>
              <TextInput
                ref={r => {
                  this._textInputRef = r;
                }}
                multiline={true}
                style={{
                  fontFamily: Globals.font_primary,
                  fontSize: 15,
                  backgroundColor: "white",
                  marginBottom: 2,
                  marginLeft: 2,
                  marginTop: 2,
                  marginRight: 2,
                  borderRadius: 5,
                  //ios
                  shadowOpacity: 0.15,
                  shadowRadius: 6,
                  shadowOffset: {
                    height: 2,
                    width: 1
                  },
                  //android
                  elevation: 2.5
                }}
                placeholder=" Auf Frage antworten.."
                keyboardType="default"
                hideUnderline={true}
                value={this.state.comment_desc}
                onChangeText={desc => this.setState({ comment_desc: desc })}
              />
            </View>
            <TouchableOpacity onPress={() => this.sendComment()}>
              <FastImage
                style={{
                  width: 22,
                  height: 22,
                  marginLeft: 10,
                  marginRight: 10,
                  marginTop: 5
                }}
                source={Globals.icon_send}
              />
            </TouchableOpacity>
          </View>
        </View>
      </View>
    );
  }
}

var styles = StyleSheet.create({
  offerItemHolder: {},
  offerContainer: {
    marginTop: 5,
    marginBottom: 5,
    marginLeft: 2,
    marginRight: 2
  }
});

module.exports = CommentItemSub;

0 个答案:

没有答案