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

React + Flux - хранить данные в состоянии компонента или в реквизитах?

Если хранилище флюсов является одноэлементным, который поддерживает состояние данных, почему компоненты используют setState, а не setProps при доступе к магазинам? Разве это не означает, что я начал сохранять состояние приложения в двух (или более) местах?

Как документация Flux/React, так и примеры, похоже, указывают на то, что setState является предпочтительным решением, но у меня был интересный разговор с несколькими коллегами на работе и задавался вопросом, встретил ли кто-нибудь еще этот

Изменить: Вы можете видеть, о чем я говорю в этом URL: https://github.com/facebook/flux/blob/master/examples/flux-chat/js/components/ThreadSection.react.js

Обратите внимание, что ThreadSection является дочерним компонентом, который извлекает данные непосредственно из хранилища и использует его как состояние.

Если вы будете следовать "Реагировать", я бы ожидал, что состояние будет управляться хранилищем, а не дочерним компонентом.

Решение, о котором мы думали, это получить все магазины в компоненте верхнего уровня (в качестве реквизита) и передать их дочерним компонентам по мере необходимости. Но это становится довольно уродливым довольно быстро.

Мы делаем это потому, что setProps не работает с дочерними компонентами

4b9b3361

Ответ 1

Поймите, что у вас должно быть 2 вида компонентов. Компоненты состояния и компоненты просмотра.

Компоненты состояния могут иметь 3 типа состояний: начальное состояние, пользовательское входное состояние и состояние хранилища данных.

Компоненты с выражением состояния - это как небольшие точки входа в "виджет", который вы собираете. Нет более простой точки входа для приложения для нисходящей зависимости или инъекции данных, поскольку все эти виджеты имеют свои собственные изолированные жизненные циклы. Вот почему они сами должны получать доступ и слушать магазины.

Помимо свойств поведения, компоненты состояния не получают фактических данных через восходящие свойства.

Компоненты stateful управляют своим собственным состоянием и передают их своим дочерним пользователям для рендеринга через свойства downstream.

Компоненты stateful обычно не отображают непосредственно элементы html DOM. Они больше похожи на контроллеры в MVC и используют другие компоненты Dumber, такие как представления в MVC, для фактического отображения элементов DOM.

Компоненты Dumber похожи на представления, поэтому они содержат только логику для отображения элементов DOM. Думайте о них как о шаблонах handlebars.js, которые получают только свойства и просто визуализируют их в DOM-элементы, возможно, с помощью циклов и т.д. Они являются рендерами без сохранения.

Надеюсь, это ответит на ваш вопрос.

Ответ 2

Согласно официальной документации, магазин должен обновить состояние родительского компонента и передать его через реквизиты своих детей:

Когда он получает событие из магазина, он сначала запрашивает новые данные, которые ему нужны, через общедоступные методы получения. Затем он вызывает свои собственные методы setState() или forceUpdate(), вызывая его метод render() и метод render() всех его потомков.

Мы часто передаем все состояние хранилища по цепочке представлений в одном объекте, позволяя различным потомкам использовать то, что им нужно. В дополнение к тому, что поведение контроллера подобно началу иерархии и, таким образом, сохраняет наши представления потомков как можно более функционально чистые, передача всего состояния магазина в одном объекте также приводит к уменьшению количества реквизитов нам нужно управлять.

(facebook flux docs - Обзор)

Ответ 3

Имеет смысл хранить данные хранилища в состоянии компонента, это связано с тем, что реквизит может меняться родительским компонентом с componentWillReceiveProps. Поэтому имеет смысл обновлять state каждый раз:

  • происходит событие изменения хранилища и
  • всякий раз, когда реквизит изменяется (перевод производных данных, относящихся только к самому компоненту в состояние)

Ниже приведен пример компонента, который обновляет прослушивание хранилища рефлекса , а также изменения реквизита. Я редко использую this.props в функции render, вместо этого я изменяю их (создаю производные данные, которые используются только в самом компоненте), когда появляются новые реквизиты. Я постоянно сталкиваюсь с этим шаблоном, поэтому также могу записать это:

var SampleComponent = React.createClass({
    mixins: [Reflux.ListenerMixin],

    // reusable helper function to build state object
    buildStateFromProps: function(props) {
        return {
            actualHeight: props.height + 20
        }
    },

    // default props if no such was set by a parent component
    getDefaultProps: function() {
        return {
            height: 100
        };
    },

    // initial state with all value set to something default
    // even using buildStateFromProps with default props
    getInitialState: function() {
        // this.props is built before this.state
        var state = buildStateFromProps(this.props);
        // append default data from store
        state.text = '';
    },

    // happens when the parent component send different 
    // props data
    componentWillReceiveProps: function(nextProps) {
        // building derivative data from new props
        // reusing buildStateFromProps
        this.setState(buildStateFromProps(nextProps));
    },

    // setting up store to be used by the component
    componentDidMount: function() {
        // this.listenTo is a helper function ListenerMixin
        this.listenTo(sampleStore, sampleUpdated);
    },

    // is called from the sampleStore update
    sampleUpdated: function(sampleData) {
        this.setState({
            text: sampleData.text
        });
    },

    render: function() {
        return (
            // ... 
            // using this.state.text from store updates and
            // this.state.height from prop updates
        );
    }
});

Причина, по которой я отправляю данные реквизита, заключается в том, чтобы избежать загромождения функции рендеринга. В противном случае функция рендеринга будет содержать много кода, который на самом деле не связан с "рендерингом" компонента. Кроме того, если эти производные данные используются в других частях приложения, тогда легко вытащить его из компонента и поместить в магазин.

Надеюсь, что это поможет.

Ответ 4

Действительный ответ на этот вопрос скрыт в комментариях к предыдущему ответу:

@idolize вы также можете передавать магазины в контекстах React (скрытый, еще не официально задокументированная функция). Это очень приятно, потому что вы не нужно делать все, что проходит по иерархии. Есть несколько статьи о контекстах, ищите его онлайн! - Andy Jul 17 '15 at 18:41