При установке состояния компонента из реквизита

Недавно я работал над Root Route (в стадии разработки), приложением MERN, целью которого является обеспечение недорогой дорожной карты на пути к тому, чтобы стать веб-разработчиком. Подумайте о Duolingo для веб-разработчиков или о платных функциях Paths от Codecademy.

Мы используем React для пользовательского интерфейса и экспериментируем с различными способами установки состояния в компонентах, которые получают реквизиты. Я рассмотрю несколько методов.

Быстрые обращения - JSX

1. Синтаксис JSX позволяет нам смешивать Javascript и HTML в уникальный инструмент для React. Приведенный ниже код отобразит на странице строку «Hello, World» (после добавления операторов импорта и экспорта вверху и внизу соответственно).

class App extends Component {
  render() {
    const hello = "Hello, World";
    return (
      <div>
        <p>{hello}</p>
      </div>
    );
  }
}

2. Мы также можем вызывать отдельные компоненты внутри других компонентов. Приведенный ниже фрагмент также отобразит на странице «Hello, World» благодаря операторам return.

class App extends Component {
  render() {
    return (
      <div>
        <Helloworld />
      </div>
    );
  }
}

class Helloworld extends Component {
  render() {
    const hello = "Hello, World";
    return (
      <p>{hello}</p>
    );
  }
}

Быстрые хиты - Реквизит

3. Если в компоненте «Helloworld» мы хотим вызвать значения, хранящиеся в компоненте «App», мы можем передать это значение как реквизиты, используя приведенный ниже синтаксис ES6. Свойства используются в React для передачи данных от родительского компонента к дочернему компоненту.

class App extends Component {
  render() {
    const hello = "Hello, World";

    return (
      <div>
        <Helloworld helloprop={hello} />
      </div>
    );
  }
}

const Helloworld = props => <p>{props.helloprop}</p>;

4. НО мы также можем обойтись без пропуска props без указания его в качестве аргумента. Это также отобразит на странице «Hello, World».

class App extends Component {
  render() {
    return (
      <div>
        <Helloworld helloprop="Hello, World" />
      </div>
    );
  }
}

class Helloworld extends Component {
  render() {
    return (
      <p>{this.props.helloprop}</p>
    );
  }
}

Быстрые обращения - Состояние

5. Мы также можем передавать значения реквизита из состояния компонента. Состояние - это доступная для чтения и записи информация для конкретного компонента, которая обеспечивает интерактивность в наших компонентах React. Наш компонент будет повторно визуализироваться при изменении состояния. Приведенный ниже фрагмент также отображает «Hello, World» на странице…

class App extends Component { 
  state = {
    hellostate: "Hello, World"
  }
  render() {
    return (
      <div>
        <Helloworld helloprop={this.state.hellostate} />
      </div>
    );
  }
}

class Helloworld extends Component {
  render() {
    return (
      <p>{this.props.helloprop}</p>
    );
  }
}

6.… И мы можем установить состояние непосредственно из props, по-прежнему без указания props в качестве параметра или использования метода жизненного цикла setState ().

class App extends Component { 
  state = {
    hellostate: "Hello, World"
  }
  render() {
    return (
      <div>
        <Helloworld helloprop={this.state.hellostate} />
      </div>
    );
  }
}

class Helloworld extends Component {
  state = {
    hellostatetwo: this.props.helloprop
  }
  render() {
    return (
      <p>{this.state.hellostatetwo}</p>
    );
  }
}

Что дает? Все в порядке или мы что-то упускаем из виду?

Ответ, на который я остановился: может быть! И пока это нормально. Оказывается, в большинстве случаев все вышеперечисленное может быть приемлемым, но, как и в случае с большинством концепций, могут возникнуть ошибки в зависимости от использования. Благодаря этому вопросу из React Docs и этой ветке StackOverflow за некоторую ясность по этому поводу.

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

Компоненты класса всегда должны вызывать базовый конструктор с props.

Когда вы передаете props в this, свойства назначаются this, поэтому мы можем использовать значение this.props внутри конструктора.

Очевидно, в сообществе до сих пор ведутся споры о намерениях этой спецификации. Некоторые причины, которые были предложены, включают:

  • Подклассы
  • Будущая совместимость

7. Это похоже на этот фрагмент ниже. Это интересно, потому что, как мы видели, реквизиты доступны без этого шага.

class HelloWorld extends React.Component {   
   constructor(props) {     
      super(props);     
      this.state = {
        hellostate: this.props.hello
      };   
   }   
   //... 
}

НО! Мы знаем, что не можем установить состояние напрямую, верно? Нам всегда нужно использовать setState()? Неправильный!

Фактически, согласно документации, вам не следует называть setState() в constructor(). Вместо этого, если вашему компоненту необходимо использовать локальное состояние, присвойте начальное состояние this.state непосредственно в конструкторе .

8. Хорошо, но даже если мы продолжим, как описано в последнем фрагменте кода, мы снова ошибаемся. Фактически, документы называют этот случай именно антипаттерном.

Избегайте копирования реквизита в состояние! Это распространенная ошибка:

constructor(props) {
 super(props);
 // Don't do this!
 this.state = { color: props.color };
}

Здесь три проблемы:

  1. В этом нет необходимости: вы можете (и должны) использовать this.props.color непосредственно вместо того места, где вы планировали использовать this.state.color.
  2. Мы искажаем наш источник информации: мы всегда хотим поддерживать «единый источник правды» о данных, содержащихся в this.props.color. В этом случае это должны быть только данные, передаваемые в качестве свойств нашему компоненту, и они не должны изменяться.
  3. Этот шаблон создает ошибки: обновления свойства color не отражаются в состоянии.

На первый взгляд, существует только один вариант использования для установки состояния непосредственно из реквизита: Намеренное игнорирование обновлений реквизита.

Это не кажется обычным явлением, поэтому будьте осторожны, прежде чем продолжить. Поскольку мы хотим разобраться в этом конкретном случае, имеет смысл переименовать опору в initialColor или defaultColor. Затем вы можете заставить компонент сбросить свое внутреннее состояние, изменив его key, когда это необходимо.

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

Мысли? Дайте мне знать, как вы к этому подходите, в комментариях.

Похоже, что за этим следует внимательно следить в документации React, когда вы разрабатываете свой собственный проект. Удачи!

Привет, Кристи Бирн, Мелика Калбаси и Линдси Уолкер из Root Route.