Зберігання об’єкта у стані компонента React?


76

Чи можна зберігати об'єкт у стані компонента React? Якщо так, то як ми можемо змінити значення ключа в цьому об’єкті за допомогою setState? Я думаю, що синтаксично не дозволяється писати щось на зразок:

this.setState({ abc.xyz: 'new value' });

У подібних рядках я маю ще одне запитання: чи нормально мати набір змінних у компоненті React, щоб їх можна було використовувати в будь-якому методі компонента, замість того, щоб зберігати їх у стані?

Ви можете створити простий об'єкт, який вміщує всі ці змінні, і розмістити його на рівні компонента, подібно до того, як ви оголошуєте будь-які методи на компоненті.

Дуже ймовірно трапляються ситуації, коли ви включаєте багато комерційної логіки у свій код, і для цього потрібно використовувати багато змінних, значення яких змінюються кількома методами, а потім ви змінюєте стан компонента на основі цих значень.

Отже, замість того, щоб зберігати всі ці змінні в стані, ви зберігаєте лише ті змінні, значення яких повинні бути безпосередньо відображені в інтерфейсі користувача.

Якщо такий підхід кращий за перше запитання, яке я написав тут, тоді мені не потрібно зберігати об’єкт у стані.

Відповіді:


38

На додаток до публікації kiran, є помічник оновлення (раніше аддон реагування ). Це можна встановити за допомогою npm за допомогоюnpm install immutability-helper

import update from 'immutability-helper';

var abc = update(this.state.abc, {
   xyz: {$set: 'foo'}
});

this.setState({abc: abc});

Це створює новий об’єкт із оновленим значенням, а інші властивості залишаються незмінними. Це більш корисно, коли вам потрібно робити такі речі, як натискання на масив і встановлення деяких інших значень одночасно. Деякі люди використовують його скрізь, оскільки він забезпечує незмінність.

Якщо ви зробите це, ви можете мати наступне, щоб компенсувати продуктивність

shouldComponentUpdate: function(nextProps, nextState){
   return this.state.abc !== nextState.abc; 
   // and compare any props that might cause an update
}

Тому я уявляю, що було б набагато простіше просто зберігати стан у чомусь, крім того this.state, і дзвонити в render()будь-який час, коли ви щось змінюєте всередині нього; чи вважається це повним ні-ні серед досвідчених розробників React?
Енді,

render - це чиста функція, вона насправді нічого не робить . Його викликає реакція, коли є оновлення, а оновлення викликаються викликами setState. Найкращі практики кажуть, що ваш візуалізатор повинен видавати однакові результати для одного і того ж реквізиту та стану. Це також дозволяє прості оптимізації, такі як shouldComponentUpdate.
Brigand

Ого, я так довго був далеко від СО? Я насправді використовував деякі основні реактивні інструменти для дзвінків, forceUpdate()коли змінювались дані моделі Backbone. Через це я можу просто перевизначити shouldComponentUpdateповернення false. renderвсе одно видає однакові результати для того самого propsі "стану" (тобто моделі Backbone, я нічого не зберігаю this.state).
Енді,

1
@Sebastialonso require('react-addons-update')і звичайно встановіть його.
Brigand

1
Здається, цей помічник тепер застарілий, і замість цього рекомендується ця бібліотека: github.com/kolodny/immutability-helper
asiop

88
  1. this.setState({ abc.xyz: 'new value' });синтаксис не допускається. Ви повинні здати весь об’єкт.

    this.setState({abc: {xyz: 'new value'}});
    

    Якщо у вас є інші змінні в abc

    var abc = this.state.abc;
    abc.xyz = 'new value';
    this.setState({abc: abc});
    
  2. Ви можете мати звичайні змінні, якщо вони не покладаються на this.props і this.state.


13
Якщо ви хочете зберегти в об’єкті інші властивості, корисний такий метод, як розширення підкреслення :this.setState({abc: _.extend(this.state.abc, {xyz: 'new value'})});
smhg

1
@smhg не зовсім, updateє більш потужним тим, що підтримує команди для зміни складних об'єктів усередині стану. Я думаю, коли ці спеціальні функції вам не потрібні_.extend що набагато чіткіший синтаксис, особливо для тих, хто читає код пізніше і не знайомий з метою update.
Золтан,

2
@smhg, щоб додати до свого, ви можете використовувати, Object.assignякщо ваш браузер підтримує ES6 (або просто використовувати поліфіл)
Jay

1
@kiran, встановлюючи складний об'єкт змінною, НЕ копіює його, він просто робить інше посилання на той самий об'єкт. Отже, var abc = this.state.abc; abc.xyz = 'new value'; це те саме, що this.state.abc.xyz='new value'
ясонсемінара

1
Ця відповідь виглядає підозріло як OP змінює стан безпосередньо, що є великим ні-ні. Якщо припустити, що в ньому abcє лише примітивні поля, правильним першим рядком має бутиvar abc = { ...this.state.abc };
Chris G


15

this.setState({abc: {xyz: 'new value'}});НЕ працюватиме, оскільки state.abcбуде повністю перезаписаний, а не об’єднаний.

Це працює для мене:

this.setState((previousState) => {
  previousState.abc.xyz = 'blurg';
  return previousState;
});

Якщо я не читаю документи неправильно, Facebook рекомендує вказаний вище формат. https://facebook.github.io/react/docs/component-api.html

Крім того, я вважаю, що найпрямішим способом без мутуючого стану є безпосереднє копіювання за допомогою оператора розширення / відпочинку ES6:

const newState = { ...this.state.abc }; // deconstruct state.abc into a new object-- effectively making a copy
newState.xyz = 'blurg';
this.setState(newState);

Я перевірив ваш перший спосіб використання, componentDidUpdate()і він правильно тримав попередній стан, при цьому this.setState({[abc.xyz]: 'blurg'})даючи неправильний попередній стан, тому я припускаю, що це добре.
Мартін Доусон,

Попередня держава насправді не була попередньою державою. Це був поточний стан, що є неправильним.
Мартін Доусон,


previousState.abc.xyz = 'blurg';мутує поточний стан, який є анти-шаблоном у React.
Еміль Бержерон,

8

Незважаючи на те, що це можна зробити за допомогою помічника незмінюваності або подібного, я не хочу додавати зовнішні залежності до свого коду, якщо це не потрібно. Коли мені потрібно це зробити, я використовую Object.assign. Код:

this.setState({ abc : Object.assign({}, this.state.abc , {xyz: 'new value'})})

Може використовуватися і в атрибутах подій HTML, приклад:

onChange={e => this.setState({ abc : Object.assign({}, this.state.abc, {xyz : 'new value'})})}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.