ReactJS состояние против проп

Возможно, это грань между ответом и мнением, но я возвращаюсь к тому, как структурировать компонент ReactJS по мере роста сложности и использования некоторого направления.

Исходя из AngularJS, я хочу передать свою модель в компонент как свойство и заставить компонент напрямую изменять модель. Или я должен разделить модель на различные свойства state и скомпилировать ее вместе при отправке обратно в восходящий поток? Как работает ReactJS?

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

var PostEditor = React.createClass({
  updateText: function(e) {
    var text = e.target.value;
    this.props.post.text = text;
    this.forceUpdate();
  },
  render: function() {
    return (
      <input value={this.props.post.text} onChange={this.updateText}/>
      <button onClick={this.props.post.save}/>Save</button>
    );
  }
});

Что кажется неправильным.

Это более эффективный способ сделать наше свойство модели text state и скомпилируйте его обратно в модель перед сохранением как:

var PostEditor = React.createClass({
  getInitialState: function() {
    return {
      text: ""
    };
  },
  componentWillMount: function() {
    this.setState({
      text: this.props.post.text
    });
  },
  updateText: function(e) {
    this.setState({
      text: e.target.value
    });
  },
  savePost: function() {
    this.props.post.text = this.state.text;
    this.props.post.save();
  },
  render: function() {
    return (
      <input value={this.state.text} onChange={this.updateText}/>
      <button onClick={this.savePost}/>Save</button>
    );
  }
});

Это не требует вызова this.forceUpdate(), но по мере роста модели (сообщение может иметь автора, тему, теги, комментарии, рейтинги и т. д.) компонент становится действительно сложным.

Первый способ с ReactLink можно использовать? р>

117 голосов | спросил nicholas 6 Mayam14 2014, 00:18:23

6 ответов


0

Ваш второй подход больше похож на это. React заботится не столько о моделях, сколько о значениях и о том, как они проходят через ваше приложение. В идеале ваша модель поста должна храниться в одном компоненте в корне. Затем вы создаете дочерние компоненты, каждый из которых использует части модели.

Вы можете передавать обратные вызовы дочерним элементам, которым необходимо изменить ваши данные, и вызывать их из дочернего компонента.

Модификация this.props или this.state напрямую не является хорошей идеей, потому что React не сможет принять изменения. Это потому, что React делает небольшое сравнение вашего поста, чтобы определить, изменился ли он.

Я сделал это jsfiddle, чтобы показать, как данные могут перетекать из внешнего во внутренний компонент:

http://jsfiddle.net/jxg/M3CLB/

Метод handleClick показывает 3 способа (im) правильного обновления состояния:

 var Outer = React.createClass({

  getInitialState: function() {
    return {data: {value: 'at first, it works'}};
  },

  handleClick: function () {

    // 1. This doesn't work, render is not triggered.
    // Never set state directly because the updated values
    // can still be read, which can lead to unexpected behavior.

    this.state.data.value = 'but React will never know!';

    // 2. This works, because we use setState

    var newData = {value: 'it works 2'};
    this.setState({data: newData});

    // 3. Alternatively you can use React's immutability helpers
    // to update more complex models.
    // Read more: http://facebook.github.io/react/docs/update.html

    var newState = React.addons.update(this.state, {
      data: {value: {$set: 'it works'}}
    });
    this.setState(newState);
 },

  render: function() {
      return <Inner data={this.state.data} handleClick={this.handleClick} />;
  }
});
ответил jxg 6 Maypm14 2014, 20:44:50
0

Обновление 2016 года . Реакция изменилась, и объяснение «реквизит против состояния» стало очень простым. Если компоненту необходимо изменить данные - поместите его в состояние, иначе в реквизит. Потому что реквизиты теперь доступны только для чтения .

Какая разница между реквизитом и состоянием?

Хорошее объяснение можно найти здесь . (полная версия)

Изменение реквизита и состояния

ответил mrvol 16 Jpm1000000pmFri, 16 Jan 2015 18:56:09 +030015 2015, 18:56:09
0

Из документа React

  

реквизиты являются неизменными: они передаются от родителя и «принадлежат» родителю. Для реализации взаимодействий мы вводим изменяемое состояние компонента. this.state является частным для компонента и может быть изменено путем вызова this.setState (). Когда состояние обновляется, компонент перерисовывается сам.

From TrySpace : когда реквизиты (или состояние) обновляются (через setProps /setState или parent), компонент также перерисовывается.

ответил Fizer Khan 11 J0000006Europe/Moscow 2014, 15:47:22
0

Чтение из мышления в React :

  

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

     
  1. Он передается от родителя через реквизит? Если так, то, вероятно, нет   государство.
  2.   
  3. Изменится ли он с течением времени? Если нет, то, вероятно, это не состояние.

  4.   
  5. Можете ли вы рассчитать его на основе любого другого состояния или реквизита в вашем       составная часть? Если это так, это не состояние.

  6.   
ответил onmyway133 27 PM00000080000002531 2015, 20:58:25
0

Я не уверен, отвечаю ли я на ваш вопрос, но обнаружил, что, особенно в большом /растущем приложении, шаблон Контейнер /Компонент работает невероятно хорошо.

По сути, у вас есть два компонента React:

  • «чистый» компонент отображения, который имеет дело со стилем и взаимодействием DOM;
  • компонент контейнера, который имеет дело с доступом /сохранением внешних данных, управлением состоянием и отображением компонента отображения.

Пример

N.B. Этот пример, вероятно, слишком прост, чтобы проиллюстрировать преимущества этого шаблона, поскольку он достаточно многословен для такого простого случая.

 /**
 * Container Component
 *
 *  - Manages component state
 *  - Does plumbing of data fetching/saving
 */

var PostEditorContainer = React.createClass({
  getInitialState: function() {
    return {
      text: ""
    };
  },

  componentWillMount: function() {
    this.setState({
      text: getPostText()
    });
  },

  updateText: function(text) {
    this.setState({
      text: text
    });
  },

  savePost: function() {
    savePostText(this.state.text);
  },

  render: function() {
    return (
      <PostEditor
        text={this.state.text}
        onChange={this.updateText.bind(this)}
        onSave={this.savePost.bind(this)}
      />
    );
  }
});


/**
 * Pure Display Component
 *
 *  - Calculates styling based on passed properties
 *  - Often just a render method
 *  - Uses methods passed in from container to announce changes
 */

var PostEditor = React.createClass({
  render: function() {
    return (
      <div>
        <input type="text" value={this.props.text} onChange={this.props.onChange} />
        <button type="button" onClick={this.props.onSave} />
      </div>
    );
  }
});

Преимущества

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

  • может быть легко повторен с различными наборами реквизитов, используя что-то вроде реагирующий компонент-детская площадка
  • может быть упакован в другой контейнер для различного поведения (или объединен с другими компонентами для создания больших частей вашего приложения

У вас также есть контейнерный компонент, который имеет дело со всеми внешними коммуникациями. Это должно упростить гибкость доступа к вашим данным, если позже вы внесете какие-либо серьезные изменения *.

Этот шаблон также упрощает написание и реализацию модульных тестов.

Пройдя несколько раз итерацию большого приложения React, я обнаружил, что этот шаблон делает вещи относительно безболезненными, особенно если у вас есть большие компоненты с вычисленными стилями или сложными взаимодействиями DOM.

* Ознакомьтесь с шаблоном потока и посмотрите на Marty.js , который в значительной степени вдохновил этот ответ (и я много использовал в последнее время) Redux act-redux ), которые очень хорошо реализуют этот шаблон.

  

Примечание для тех, кто читает это в 2018 году или позже:

     

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

ответил Jim O'Brien 9 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowWed, 09 Sep 2015 03:48:14 +0300 2015, 03:48:14
0

Я думаю, что вы используете анти-шаблон, который Facebook уже объяснил на этом ссылка

Вот что вы нашли:

 React.createClass({
  getInitialState: function() {
    return { value: { foo: 'bar' } };
  },

  onClick: function() {
    var value = this.state.value;
    value.foo += 'bar'; // ANTI-PATTERN!
    this.setState({ value: value });
  },

  render: function() {
    return (
      <div>
        <InnerComponent value={this.state.value} />
        <a onClick={this.onClick}>Click me</a>
      </div>
    );
  }
});

При первом рендеринге внутренний компонент будет иметь значение {foo: 'bar'} в качестве значения prop. Если пользователь нажимает на привязку, состояние родительского компонента будет обновлено до {value: {foo: 'barbar'}}, запуская процесс повторного рендеринга внутреннего компонента, который получит {foo: 'barbar'} как новое значение для опоры.

Проблема в том, что, поскольку родительский и внутренний компоненты совместно используют ссылку на один и тот же объект, когда объект мутирует в строке 2 функции onClick, пропеллер, который имел внутренний компонент, изменится. Таким образом, когда начинается процесс повторного рендеринга и должен вызываться shouldComponentUpdate, this.props.value.foo будет равно nextProps.value.foo, потому что фактически this.props.value ссылается на тот же объект, что и nextProps.value.

Следовательно, поскольку мы пропустим изменение в подпорке и закроем процесс повторного рендеринга, пользовательский интерфейс не будет обновлен с 'bar' до 'barbar'

ответил Alex Nguyen 21 stEurope/Moscowp30Europe/Moscow09bEurope/MoscowWed, 21 Sep 2016 12:35:03 +0300 2016, 12:35:03

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132