Подтвердить что ты не робот

Как обращаться с древовидными объектами в редукторах Redux?

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

В качестве примера возьмем комментарии reddit: каждый комментарий может содержать комментарии пользователя, которые могут иметь собственные комментарии и т.д. Для упрощения, комментарий представляет собой запись типа {id, pageId, value, children}, при этом pageId является страницей reddit.

Как можно моделировать редуктор вокруг этого? Я думал о том, что редуктор представляет собой карту → идентификатор комментариев, где вы можете фильтровать страницу с помощью pageId.

Проблема в том, что, например, когда мы хотим добавить комментарий к вложенному: нам нужно создать запись в корневой части карты, а затем добавить свой идентификатор в родительское дочернее свойство. Чтобы отобразить все комментарии, мы 'd нужно получить все из них, отфильтровать те, что мы наверху (которые будут храниться в редукторах страниц, например, упорядоченный список), а затем повторять их, извлекать из объектов комментариев, когда мы сталкиваемся с детьми, использующими рекурсию.

Есть ли лучший подход, чем этот, или он ошибочен?

4b9b3361

Ответ 1

Официальное решение этого - использовать normalizr, чтобы сохранить ваше состояние следующим образом:

{
  comments: {
    1: {
      id: 1,
      children: [2, 3]
    },
    2: {
      id: 2,
      children: []
    },
    3: {
      id: 3,
      children: [42]
    },
    ...
  }
}

Вы правы, что вам нужно connect() компонент Comment, чтобы каждый из них мог рекурсивно запрашивать children, который он заинтересован в хранилище Redux:

class Comment extends Component {
  static propTypes = {
    comment: PropTypes.object.isRequired,
    childComments: PropTypes.arrayOf(PropTypes.object.isRequired).isRequired
  },

  render() {
    return (
      <div>
        {this.props.comment.text}
        {this.props.childComments.map(child => <Comment key={child.id} comment={child} />)}
      </div> 
    );
  }
}

function mapStateToProps(state, ownProps) {
  return {
    childComments: ownProps.comment.children.map(id => state.comments[id])
  };
}

Comment = connect(mapStateToProps)(Comment);
export default Comment;

Мы считаем, что это хороший компромисс. Вы передаете Comment в качестве опоры, но компонент извлекает childrenComments из хранилища.

Ответ 2

Структура вашего магазина (редуктора) может отличаться от вашей желаемой модели просмотра (которую вы передаете в качестве реквизита для компонентов). Вы можете просто сохранить все комментарии в массиве и сопоставить их с деревом по ссылкам в mapStateToProps на высокоуровневом "интеллектуальном" компоненте. Вы получите простое управление состоянием в редукторе и удобную модель представления компонентов для работы.