Реактивный компонент не перерисовывается, хотя Object in props изменяется - PullRequest
0 голосов
/ 05 ноября 2018

Я знаю, есть много-много похожих вопросов .. ** Двойной сигнал! **

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

class CsvListDropdown extends Component {
    constructor(props) {
        super(props);
        this.state = { sessions: props.sessions }
        this csvsInSession = this.csvsInSession.bind(this);
    }

    csvsInSession(sessions) {
        return (sessions
            .map(keys => Object.entries(keys)[2][1])
            .map((csv, i) => (
                <option value={csv} key={i}>{csv}</option>
            ))
        )
    }

    render() {
        const { isLoading } = this.props
        if (isLoading) { blablabla.. }
        else {
            return (
                ...
                <select value={this.props.sessions[0].currentCsv}>
                    {this.csvsInSession(this.state.sessions)}
                </select>
                ...
            )
        }
    }
}

export default withTracker(() => {
    const handle = Meteor.subscribe('sessions');
    return {
      isLoading: !handle.ready(),
      sessions: Sessions.find({}).fetch() 
    };
})(CsvListDropdown);

Теперь от клиента я записываю другой документ в коллекцию Sessions , содержащую имя файла .csv, пока этот новый файл csv загружается на удаленный сервер. console.log(this.props.sessions) дает мне массив, который актуален. Но сам компонент не выполняет рендеринг.

Я тоже не понимаю: console.log(this.state.sessions) возвращает undefined. (примечание: состояние )

Что я пробовал до сих пор:

  • {this.csvsInSession(this.props.sessions)} (примечание: реквизит )
  • Добавление withTracker / State / Props к родительскому компоненту и передача объекта sessions из state или props в качестве параметров дочернему компоненту, который должен визуализации.

  • forceUpdate ()

  • componentWillUpdate ()

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

Ответы [ 2 ]

0 голосов
/ 06 ноября 2018

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

// server-side
Meteor.publish('sessions', function() {
    return Sessions.find({ userId: this.userId }, { sort: {createdAt: -1} });
});

На стороне сервера, похоже, не то место для сортировки. Это просто не имеет эффекта. Так сортируется на стороне клиента, при подписке:

// client-side
export default withTracker(() => {
    const handle = Meteor.subscribe('sessions');
    return {
      isLoading: !handle.ready(),
      sessions: Sessions.find({}, { sort: {createdAt: -1} }).fetch() 
    };
})(App)

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

<select value={this.props.sessions[0].currentCsv}>
    {this.csvsInSession(sessions)}
</select>

Итак, урок усвоен: если вы думаете, что ваш компонент реагирования не рендерится, всегда проверяйте, так ли это, прежде чем предполагать это.


В качестве побочного эффекта отладки я реструктурировал свои компоненты. Теперь Meteor.subscribe() находится внутри родительского компонента, который содержит все дочерние элементы, которые должны обрабатывать объект sessions. И объект sessions передается от родителя (великим) потомкам в качестве реквизита. Я думаю, что так легче читать и легче поддерживать.

0 голосов
/ 05 ноября 2018

this.state изменится, только если вы позвоните this.setState(), чего вы не делаете. Вы инициализируете state значением props, но только в конструкторе, когда компонент создается впервые. После этого, даже если props изменится, ваш компонент может перерисоваться, но то, что он отображает, не изменится, потому что state не был обновлен.

Фактически, по-видимому, нет никаких причин хранить данные в состоянии в этом компоненте. Это также может быть функциональный компонент представления:

function CsvListDropdown(props) {
    function csvsInSession(sessions) {
        return (sessions
            .map(keys => Object.entries(keys)[2][1])
            .map((csv, i) => (
                <option value={csv} key={i}>{csv}</option>
            ))
        )
    }

    const { isLoading } = props;
    if (isLoading) { blablabla.. }
    else {
        return (
            ...
            <select>
                {csvsInSession(props.sessions)}
            <select>
            ...
        )
    }
}

Как правило, все ваши компоненты должны быть функциональными компонентами без сохранения состояния , если только по какой-то причине им не требуется специально сохранять внутреннее состояние.

...