Как я могу улучшить производительность рекурсивного компонента в React?

#javascript #reactjs #react-native

#javascript #reactjs #react-native

Вопрос:

В моем проекте React Native Expo я создал рекурсивный компонент комментариев, который вызывает сам себя, чтобы отобразить вложенный поток комментариев.

Однако, как только количество комментариев становится слишком большим, производительность начинает снижаться там, где это не очень удобно для пользователя.Я попытался изменить структуру вызовов API для получения этих комментариев и некоторые другие незначительные настройки, но безрезультатно.

Я полагаю, что мне нужно каким-то образом использовать shouldComponentUpdate, чтобы повторно отображать только при изменении определенного состояния, в основном независимо от того, открыт комментарий или нет. свернутый.

Есть ли какие-либо способы повысить производительность рекурсивного компонента в React?

 import { FontAwesome } from "@expo/vector-icons";
import dateFns from "date-fns";
import { inject } from "mobx-react";
import PropTypes from "prop-types";
import React from "react";
import {
  ActivityIndicator,
  StyleSheet,
  TouchableHighlight,
  View
} from "react-native";
import Collapsible from "react-native-collapsible";
import HTMLView from "react-native-htmlview";
import { Text, withTheme } from "react-native-paper";
import ApiService from "../services/ApiService";

class Comment extends React.Component {
  static propTypes = {
    api: PropTypes.instanceOf(ApiService).isRequired,
    commentIds: PropTypes.arrayOf(PropTypes.number).isRequired
  };

  state = {
    comments: null
  };

  componentDidMount() {
    this.fetchStoryComments();
  }

  async fetchStoryComments() {
    const { api, commentIds } = this.props;
    try {
      let comments = await api.fetchStoryComments(commentIds);
      comments = comments.map(comment => {
        const commentCopy = comment;
        commentCopy.isCollapsed = false;
        return commentCopy;
      });
      this.setState({
        comments
      });
    } catch (error) {
      // HANDLE ERROR
    }
  }

  toggleCollapse(commentId) {
    this.setState(prevState => ({
      comments: prevState.comments.map(comment =>
        comment.id === commentId
          ? Object.assign(comment, { isCollapsed: !comment.isCollapsed })
          : comment
      )
    }));
  }

  render() {
    const { comments } = this.state;
    const { api } = this.props;

    return comments ? (
      comments.map(
        comment =>
          comment amp;amp; (
            <View key={comment.id} style={styles.commentContainer}>
              <TouchableHighlight
                onPress={() => this.toggleCollapse(comment.id)}
              >
                <View style={styles.commentHeader}>
                  <Text style={styles.commentHeaderText}>
                    {`${comment.by} ${dateFns.distanceInWordsToNow(
                      new Date(comment.time * 1000)
                    )} ago`}
                  </Text>
                  <Text style={styles.commentHeaderText}>
                    {comment.isCollapsed ? (
                      <FontAwesome name="plus" />
                    ) : (
                      <FontAwesome name="minus" />
                    )}
                  </Text>
                </View>
              </TouchableHighlight>
              <Collapsible duration={200} collapsed={comment.isCollapsed}>
                <View style={styles.comment}>
                  <HTMLView
                    addLineBreaks={false}
                    stylesheet={htmlStyles}
                    textComponentProps={{ style: styles.commentText }}
                    value={comment.text}
                  />
                  {"kids" in comment amp;amp; (
                    <View style={styles.kids}>
                      <Comment api={api} commentIds={comment.kids} />
                    </View>
                  )}
                </View>
              </Collapsible>
            </View>
          )
      )
    ) : (
      <ActivityIndicator
        style={styles.activityIndicator}
        size="small"
        color="#fff"
      />
    );
  }
}

export default inject("api")(withTheme(Comment));
 

Комментарии:

1. ограничьте количество рекурсивных итераций и скройте остальное за «подробнее»

2. Да, я обдумывал это. Возможно, это неплохая идея для временного исправления, но в долгосрочной перспективе это не так удобно для пользователей..

3. Почему бы и нет? Большинство крупных сайтов каким-то образом включают это — facebook, twitter, даже stackoverflow

4. Это правда. Я определенно оставлю это в качестве опции. Я бы предпочел бесконечную прокрутку, аналогичную компоненту FlatList.

5. Вот отличная статья о том, почему бесконечная прокрутка может быть плохой идеей: logrocket.com/blog/infinite-scroll

Ответ №1:

вы пробовали использовать flatlist вместо сопоставления множества представлений?

вот руководство, объясняющее, как его использовать.

Редактировать 1:

На самом деле вы можете использовать sectionlist, который похож на flatlist, для сложных структур, подобных той, которую вы создаете.

вот небольшой пример:

 render() {
    const a = ['comment 1 a', 'comment 2 a', 'comment 3 a'];
    const b = ['comment 1 b', 'comment 2 b'];
    const c = ['comment 1 c'];

    return (
      <View style={{ marginTop : (Platform.OS) == 'ios' ? 20 : 0 }}>
        <SectionList
          sections={[
            { comment: 'Comment a with subcomponents a', data: a },
            { comment: 'Comment b with subcomponents b', data: b },
            { comment: 'Comment c with subcomponents c', data: c },
          ]}
          renderSectionHeader={ ({section}) => <Text> { section.comment } </Text> }
          renderItem={ ({item}) => <Text> { item } </Text> }
          keyExtractor={ (item, index) => index }
        />
      </View> 
    );
  }
 

если data поле в списке разделов может быть массивом компонентов,
надеюсь, это поможет.

Комментарии:

1. Я кратко попробовал Flatlist, но у меня возникли проблемы с вложением Flatlists в Flatlists из-за характера потоковой обработки комментариев. Возможно, я ошибался. Не могли бы вы привести пример высокого уровня о том, как вы могли бы преобразовать его в FlatList?

2. Я редактирую сообщение с небольшим примером, надеюсь, это может быть полезно

3. Спасибо! Я попробую это сделать.