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

Предотвратить повторный рендеринг компонента при использовании сокращения с компонентомWillMount

У меня есть компонент React, который отправляет изменение состояния редукции в его функцию componentWillMount. Причина в том, что когда компонент загружен, ему нужно получить id от url (с питанием от react-router) и вызвать действие, которое устанавливает состояние с данными id.

Вот компонент:

class Editor extends React.Component {

    componentWillMount() {
        const { dispatch, params } = this.props
        dispatch(editItem(params.id))
    }

    render() {
        const item = this.props.item
        console.log("Editing", item)
    }
}

export default connect(state => ({item: state.item}))(Editor)

Здесь catch: render получает вызов дважды. item имеет значение undefined при первом вызове и действует на втором. В идеале его следует вызывать только один раз this.props.item на самом деле существует (после того, как действие editItem было отправлено и запущено).

В соответствии с React docs: "Если вы вызываете setState внутри этого метода, render() будет видеть обновленное состояние и будет выполняться только один раз, несмотря на то, что изменение состояния".

В redux, dispatch является эквивалентом вызова setState, так как это приводит к изменению состояния. Тем не менее, я что-то угадываю, так как работа connect по-прежнему вызывает вызов render дважды.

Есть ли способ обойти это, помимо добавления строки типа if (!item) return;?

4b9b3361

Ответ 1

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

export const LoaderWrapper = function(hasLoaded, Component, LoaderComponent, onLoad) {
    return props => {
        if (hasLoaded(props)) {
            return <Component {...props} />
        }
        else {
            if (onLoad) onLoad(props)

            return { LoaderComponent ? <LoaderComponent /> : null }
        }
    }
}

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

export default connect(state => ({item: state.item}))(LoaderWrapper(
    ((props) => !!props.item),
    Editor,
    null,
    (props) => props.dispatch(editItem(props.params.id))
))

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

Ответ 3

Что делает editItem? Он добавляет элемент в состояние редукции или уже там?

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

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

Но не зная, что такое editItem, это сложно понять. Может быть, вы можете вставить код для этого?