Реагировать компонент не сбрасывает состояние при использовании Object.assign ()? - PullRequest
0 голосов
/ 14 февраля 2020

У меня есть компонент React, который, кажется, не сбрасывает свое первоначальное состояние правильно. Я использую Object.assign (), чтобы убедиться, что переданные реквизиты имеют все поля (для ретроспективы для устаревших записей базы данных, где ключи могут быть не определены).

newProfile - полный профиль (с полем заголовка) ), а legacyProfile - это запись до добавления поля заголовка. Почему / как компонент, передающий legacyProfile, каким-то образом хранит некоторые данные из другого экземпляра (компонент, передающий newProfile), и как я могу предотвратить это, чтобы убедиться, что я всегда начинаю с fre sh profileInitialState?

const profileInitialState = {
  name: '',
  title: '',
  headline: '',
  bio: ''
}

class Bio extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      editingProfile: Object.assign(profileInitialState, this.props.profile)
    }
  }
  
  render() {
    const { profile } = this.props;
    const { editingProfile } = this.state;
    
    console.log(profile); // props profile has correct info
    console.log(editingProfile); // state profile takes on old values
    
    return (
      <div>
        <h1>{editingProfile.name}</h1>
        <h2>{editingProfile.title}</h2>
        <h3>{editingProfile.headline}</h3>
        <p>{editingProfile.bio}</p>
      </div>
    );
  }
}

const newProfile = {
  name: 'Test 1',
  title: 'Title 1',
  headline: 'Headline 1',
  bio: 'Bio 1'
}

const legacyProfile = {
  name: 'Test 2',
  title: 'Title 2',
  bio: 'Bio 2'
}

ReactDOM.render(
  <React.Fragment>
  <Bio profile={newProfile} />
  <Bio profile={legacyProfile} />
  </React.Fragment>,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root">
    <!-- This element's contents will be replaced with your component. -->
</div>

Ответы [ 2 ]

5 голосов
/ 14 февраля 2020

Object.assign назначит собственные перечислимые свойства из всех аргументов 2 и выше в объект в 1 аргументе. Так

editingProfile: Object.assign(profileInitialState, this.props.profile)

видоизменяется profileInitialState.

Эта строка похожа на

for (const [key, val] of Object.entries(this.props.profile)) {
  profileInitialState[key] = val;
}

В результате второй раз этой строки выполняется, результаты первого могут все еще существовать в profileInitialState.

Вместо этого используйте

editingProfile: Object.assign({}, profileInitialState, this.props.profile)

, чтобы создать совершенно новый объект:

const profileInitialState = {
  name: '',
  title: '',
  headline: '',
  bio: ''
}

class Bio extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      editingProfile: Object.assign({}, profileInitialState, this.props.profile)
    }
  }
  
  render() {
    const { profile } = this.props;
    const { editingProfile } = this.state;
    
    console.log(profile); // props profile has correct info
    console.log(editingProfile); // state profile takes on old values
    
    return (
      <div>
        <h1>{editingProfile.name}</h1>
        <h2>{editingProfile.title}</h2>
        <h3>{editingProfile.headline}</h3>
        <p>{editingProfile.bio}</p>
      </div>
    );
  }
}

const newProfile = {
  name: 'Test 1',
  title: 'Title 1',
  headline: 'Headline 1',
  bio: 'Bio 1'
}

const legacyProfile = {
  name: 'Test 2',
  title: 'Title 2',
  bio: 'Bio 2'
}

ReactDOM.render(
  <React.Fragment>
  <Bio profile={newProfile} />
  <Bio profile={legacyProfile} />
  </React.Fragment>,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root">
    <!-- This element's contents will be replaced with your component. -->
</div>

Или, еще более кратко:

editingProfile: { ...profileInitialState, ...this.props.profile }
0 голосов
/ 14 февраля 2020

Object.assign копирует из источника (второй аргумент) в цель (первый аргумент).

Каков ваш целевой объект? ProfileInitialState, который вы объявили вне класса Bio.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...