Як я можу скинути компонент реагування, включаючи весь перехідно доступний стан?


93

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

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

Чи існує API або шаблон для цього?

Редагувати: Я зробив тривіальний приклад, який демонструє this.replaceState(this.getInitialState())підхід і протиставляє його this.setState(this.getInitialState())підходу: jsfiddle - replaceStateбільш надійний.

Відповіді:


206

Щоб переконатися, що неявний стан браузера, про який ви згадали, і стан дітей скинуто, ви можете додати keyатрибут до кореневого компонента, що повертається render; коли він зміниться, цей компонент буде викинутий і створений з нуля.

render: function() {
    // ...
    return <div key={uniqueId}>
        {children}
    </div>;
}

Немає ярлика для скидання локального стану окремого компонента.


1
Просто з цікавості, коли ви говорите, що "компонент буде викинутий і створений з нуля", ви маєте на увазі, що віртуальний DOM буде викинутий і створений з нуля, але оновлення DOM все одно відбуватимуться на основі алгоритму diff?
nimgrg

1
@nimgrg Ні, реальні елементи DOM також будуть відтворені. (Віртуальний DOM вже відтворений на кожному рендері, тому, якщо ви хочете зберегти справжній DOM, просто не встановлюйте keyв цьому випадку значення.)
Софі Альперт,

3
@EamonNerbonne У React 0.8 клавіші використовуються лише для розрізнення між рідними елементами масиву і були проігноровані в корені. Див. Github.com/facebook/react/issues/590 .
Софі Алперт

Зверніть увагу, replaceState()і getInitialState()обидва вони застаріли в новому реакторі класу ES6. Використовуйте this.setState(this._getInitialState())замість цього. Також ви не можете назвати власну функцію ініціалізатора стану getInitialState()- реакція видає попередження - назвіть це як-небудь ще і явно зробіть це state = this._getInitialState()на верхньому рівні класу.
thom_nic

2
Чи є спосіб зробити це зсередини компонента, не вимагаючи від зовнішньої сторони передачі опори ключа?
trusktr

14

Ви насправді повинні уникати replaceStateта використовуватиsetState замість цього.

У документації сказано, що replaceState"може бути повністю видалено в майбутній версії React". Думаю, його точно буде видалено, тому щоreplaceState насправді не дрижить з філософією React. Це сприяє тому, що компонент React починає відчувати себе якось по-швейцарськи. Це протистоїть природному зростанню компонента React, що стає меншим та більш цілеспрямованим.

У React, якщо вам доводиться помилятися щодо узагальнення або спеціалізації: прагніть до спеціалізації. Як наслідок, дерево стану для вашого компонента повинно мати певну екологічну оцінку (чудово порушити це правило зі смаком, якщо ви все-таки вирішуєте бренд, який обробляє бренд).

У будь-якому випадку це те, як ви це робите. Подібно до (прийнятої) відповіді Бена вище, але так:

this.setState(this.getInitialState());

Також (як сказав Бен) для того, щоб скинути "стан браузера", потрібно видалити цей вузол DOM. Використовуйте потужність vdom та використовуйте нову keyопору для цього компонента. Нова візуалізація замінить цей компонент оптом.

Посилання: https://facebook.github.io/react/docs/component-api.html#replacestate


2
Це не буде працювати, якщо поточний стан включає будь-які властивості, які не перебувають у початковому стані. Хоча я не вірю, що це чудовий "стан" справ, якщо ви не можете якось запобігти цьому, я хотів би уникнути дивовижної поломки. Зі скиданням, яке в деяких випадках виходить з ладу, я б не в порядку , але не зі скиданням, яке тонко псує стан.
Імон Нербонн

Не впевнений, що слідую. Ви хочете сказати, що це не рівнозначно this.replaceState? Тому що це так.
wle8300

1
@ williamle8300 Вони не були б еквівалентними, якщо нове властивість буде додано до стану десь у життєвому циклі компонента між викликами getInitialState()(наприклад, в обробнику onClick). У цьому випадку це нове майно все ще буде присутнє після 2-го getInitialState().
Грем

@Graham Я вважаю, що це погана практика вводити новий стан до компонента, який ще не задекларований getInitialState. Подібно до оголошення всіх ваших змінних у функції JS у верхній частині функції. Примітка: Рішення Бена Альперта майже ідентичне моєму ... і він офіційний супровідник React!
wle8300

1
Я боюся, що функція getInitialState (), а отже і відповідь, застаріла. Оновлення було б непогано.
Martin R.

8

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

key = {нова дата (). getTime ()}

Ось приклад:

render() {
  const items = (this.props.resources) || [];
  const totalNumberOfItems = (this.props.resources.noOfItems) || 0;

  return (
    <div className="items-container">
      <PaginationContainer
        key={new Date().getTime()}
        totalNumberOfItems={totalNumberOfItems}
        items={items}
        onPageChange={this.onPageChange}
      />
    </div>
  );
}

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