React-Apollo - вызов рендера перед getDerivedStateFromProps

У меня есть компонент, который включает форму проверки для пользователя. Этот компонент запускает запрос graphql при монтировании. В компоненте Verification мне нужно использовать данные из запроса graphql, чтобы установить состояние, чтобы я мог использовать его для обновления любых значений, а затем отправить их с формой. С тех пор я узнал о getDerivedStateFromProps, и он работает над заполнением нового состояния на основе этих данных. Но данные недоступны в DOM. Как будто render вызывается перед getDerivedStateFromProps.

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

class Verification extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            company: {
                legalName: ''
            },
            openCorporatesCompany: {}
        };
    }

    handleLegalNameChange = (legalName) => {
        let company = _.cloneDeep(this.state.company);
        company.legalName = legalName;
        this.setState({
            company
        })
    };

    static getDerivedStateFromProps(next, prev) {
        let newState = _.cloneDeep(prev);
        let {openCorporates: {getEntityAttribute}} = next;

        if (getEntityAttribute && getEntityAttribute.value) {
            let openCorporatesCompany = JSON.parse(getEntityAttribute.value);
            let company = _.cloneDeep(newState.company);
            company.legalName = openCorporatesCompany.name;
            newState.openCorporatesCompany = openCorporatesCompany;
            newState.company = company;

            return newState;
        }

        return null;
    }

    render() {
        console.log(this.state);

        return (
                    <Input
                        label='Legal Name'
                        placeholder='Legal entity name...'
                        type='text'
                        subtext='Use the name your customers or clients will recognize'
                        onChange={this.handleLegalNameChange}
                        value={this.state.legalName}
                    />
        );
    }
}

export const VerificationContainer = compose(
    connect(mapStateToProps, mapDispatchToProps)
    graphql(GetEntityAttributeQuery, {
        name: "openCorporates",
        options: (props) => ({
            variables: {
                entityId: props.currentEntity.id,
                type: EntityAttributes.TypeOpenCorporates
            }
        })
    })
)(Verification);

Консольный вывод console.log(this.state) в render выглядит так:

журнал консоли

Как видите, поле обновляется в состоянии company.legalName. Но он никогда не заполняется в поле ввода:

введите описание изображения здесь

Почему вход не обновляется с новым состоянием? Это как если бы рендер был вызван до getDerivedStateFromProps.


person jrkt    schedule 17.09.2018    source источник


Ответы (2)


Я знаю вашу борьбу с реакцией и обновлением компонентов, но полагаю, что нет никаких доказательств, чтобы избавиться от этого; 80% Думаю, вам стоит попробовать любой из различных методов жизненного цикла. Раньше был componentWillReceiveProps для асинхронных вызовов, но поскольку он был помечен как небезопасный (я думаю), вы должны попробовать getDerivedStateFromProps (props, state)

getDerivedStateFromProps(props, state) {
  console.log("*************** PROPS:",  props);

  let { openCorporates: { getEntityAttribute  } } = props;

  if (getEntityAttribute  &&  getEntityAttribute.value) {
      let openCorporatesCompany = JSON.parse(getEntityAttribute.value);
      let company = _.cloneDeep(this.state.company);

      company.legalName = openCorporatesCompany.name;
      this.setState({
          openCorporatesCompany,
          company
      })
  }
}

Учтите, что я не запускал сниппет.

person Charlie    schedule 17.09.2018
comment
Я получаю эту ошибку при добавлении: Warning: Verification: getDerivedStateFromProps() is defined as an instance method and will be ignored. Instead, declare it as a static method. - person jrkt; 17.09.2018
comment
lol извините, добавьте статику в подпись, e.i. static getDerivedStateFromProps (реквизиты, состояние) {... - person Charlie; 17.09.2018
comment
Как мне успешно использовать этот метод? В нем говорится, что мне нужно вернуть объект. Передан ли объект state, объект this.state из компонента? Могу ли я просто изменить этот объект, а затем вернуть его как новое состояние? - person jrkt; 17.09.2018
comment
извините, я пока не использую response, но по сути вам следует сравнить аргументы, в данном случае next и prev, для значения if (next.openCorporates.value! == prev.openCorporates.value) {return {openCorporates: next .openCorporates}; } else return null; как в этом сообщении - person Charlie; 17.09.2018
comment
Откуда берутся следующие и предыдущие? В сигнатуре метода есть только реквизиты и состояние. Кроме того, это работает примерно в половине случаев. Если я распечатаю this.state в функции рендеринга, данные будут отображаться каждый раз. Но иногда компоненты на странице не имеют данных. Это как если бы рендеринг этого дочернего компонента вызывается перед getDerivedStateFromProps из родительского компонента. - person jrkt; 17.09.2018
comment
@JonStevens следующий и предыдущий - просто удобные имена. В моем примере я скопировал подпись из документации. При реализации метода вы переходите из одного состояния (предыдущее) в другое состояние (следующее), поэтому вам следует сравнить и вернуться соответственно; обычно следующее состояние - желаемое. Если в нем отсутствовали поля, возможно, поэтому. Итак, консоль регистрирует как следующий, так и предыдущий и создает свой объект (например, newState). Надеюсь, это поможет - person Charlie; 17.09.2018
comment
Тот же результат. По-прежнему иногда обновляет DOM только этими полями данных. - person jrkt; 17.09.2018
comment
Можете ли вы использовать фрагмент того, как сейчас выглядят файлы? - person Charlie; 17.09.2018
comment
Какой сниппет вы ищете? - person jrkt; 17.09.2018
comment
тот, который не отображает данные должным образом, в этом случае класс, содержащий getDerivedStateFromProps ... - person Charlie; 17.09.2018
comment
Я обновил свой вопрос, так как считаю, что это новая проблема. - person jrkt; 18.09.2018
comment
извините за это, похоже, вы должны вызывать componentDidUpdate () после каждого getDerivedStateFromProps, если вы хотите выполнить изменения состояния. Я обновил ваш код - person Charlie; 18.09.2018

Это закончилось тем, что помогло мне благодаря ответу @ Charlie:

static getDerivedStateFromProps(props, state) {
    let newState = _.cloneDeep(state);
    let { openCorporates: { getEntityAttribute  } } = props;

    if (getEntityAttribute  &&  getEntityAttribute.value) {
        let openCorporatesCompany = JSON.parse(getEntityAttribute.value);
        let company = _.cloneDeep(newState.company);
        company.legalName = openCorporatesCompany.name;
        newState.openCorporatesCompany = openCorporatesCompany;
        newState.company = company;
    }

    return newState;
}
person jrkt    schedule 17.09.2018