Паттерны React

Привет Хабр! Предлагаю вашему вниманию свободный перевод статьи «React Patterns» Майкла Чана, с некоторыми моими примечаниями и дополнениями.

Прежде всего хотел бы поблагодарить автора оригинального текста. В переводе я использовал понятие «Простой компонент» как обозначение Stateless Component aka Dump Component aka Component vs Container
Конструктивная критика, а так же альтернативные паттерны и фичи React приветствуются в комментах.

Оглавление
  • Простые компоненты — Stateless function
  • JSX распределение атрибутов — JSX Spread Attributes
  • Деструктуризация аргументов — Destructuring Arguments
  • Условный рендеринг — Conditional Rendering
  • Типы потомков — Children Types
  • Массив как потомок — Array as children
  • Функция как потомок — Function as children
  • Функция в render — Render callback
  • Проход по потомкам — Children pass-through
  • Перенаправление компонента — Proxy component
  • Стилизация компонентов — Style component
  • Переключатель событий — Event switch
  • Компонент-макет — Layout component
  • Компонент-контейнер — Container component
  • Компоненты высшего порядка — Higher-order component

Поехали!

Stateless function


Функция без состояния ( далее Простые Копоненты) прекрасный способ определить универсальный компонент. Они не содержат состояния (state) или ссылку на DOM элемент (ref), это просто функции.

const Greeting = () => <div>Hi there!</div>

В них передаются параметры (props) и контекст

const Greeting = (props, context) =>
  <div style={{color: context.color}}>Hi {props.name}!</div>

Они могут определять локальные переменные, если используете блоки ({})

const Greeting = (props, context) => {
  const style = {
    fontWeight: "bold",
    color: context.color,
  }
  return <div style={style}>{props.name}</div>
}

Но вы можете получить тот же результат, если используете еще одну функцию

const getStyle = context => ({
  fontWeight: "bold",
  color: context.color,
})
const Greeting = (props, context) =>
  <div style={getStyle(context)}>{props.name}</div>

Они могут определить defaultProps, propTypes и contextTypes

Greeting.propTypes = {
  name: PropTypes.string.isRequired
}
Greeting.defaultProps = {
  name: "Guest"
}
Greeting.contextTypes = {
  color: PropTypes.string
}

JSX Spread Attributes


Распределение атрибутов это фитча JSX. Такой синтаксический наворот, чтобы передавать все свойства объекта как атрибуты JSX

Эти два примера эквивалентны:

— props написаны как атрибуты:

<main className="main" role="main">{children}</main>

— props «распределены» из объекта:

<main {...{className: "main", role: "main", children}} />

Используйте перенаправление props в создаваемый объект

const FancyDiv = props =>
  <div className="fancy" {...props} />

Теперь вы можете быть уверены, что нужный атрибут будет присутствовать (className), так же как и те которые вы не указали напрямую в функции а передали в нее вместе с props

<FancyDiv data-id="my-fancy-div">So Fancy</FancyDiv>

Результат:

<div className="fancy" data-id="my-fancy-div">So Fancy</div>

Имейте ввиду, что порядок имеет значение. если props.className определено, то это свойство перепишет className определенное в FancyDiv

<FancyDiv className="my-fancy-div" />

Результат:

<div className="my-fancy-div"></div>

We can make FancyDivs className always “win” by placing it after the spread props ({…props}).
Вы можете сделать так, что ваше свойство всегда перепишет переданные через props

const FancyDiv = props =>
  <div {...props} className="fancy" />

Есть более изящный подход — объединить оба свойства.

const FancyDiv = ({ className, ...props }) =>
  <div
    className={["fancy", className].join(' ')}
    {...props}
  />

Destructuring Arguments


Деструктурирующее присвоение это фича стандарта ES2015. Она отлично сочетается с props для Простых Компонентов.

Эти примеры эквивалентны

const Greeting = props => <div>Hi {props.name}!</div>
const Greeting = ({ name }) => <div>Hi {name}!</div>

Синтаксис оператора rest (…) позволяет собрать оставшиеся свойства в объект

const Greeting = ({ name, ...props }) =>
  <div>Hi {name}!</div>

Далее этот объект может быть использован для передачи не выделенных свойств далее в созданном компоненте

const Greeting = ({ name, ...props }) =>
  <div {...props}>Hi {name}!</div>

Avoid forwarding non-DOM props to composed components. Destructuring makes this very easy because you can create a new props object without component-specific props.

Conditional Rendering


Можете использовать обычный if/else синтаксис в компонентах. Но условные (тернарные) операторы это ваши друзья

if

{condition && <span>Rendered when `truthy`</span> }

unless

{condition || <span>Rendered when `falsey`</span> }

if-else (tidy one-liners)

{condition
  ? <span>Rendered when `truthy`</span>
  : <span>Rendered when `falsey`</span>
}

if-else (big blocks)

{condition ? (
  <span>
    Rendered when `truthy`
  </span>
) : (
  <span>
    Rendered when `falsey`
  </span>
)}

* Я предпочитаю не использовать конструкции из последнего примера, гораздо нагляднее в данном случае будет использование обычного if/else, хотя все зависит от конкретного кода.

Children Types


React может рендерить потомков любого типа. В основном это массив или строка

Строка

<div>
  Hello World!
</div>

Массив

<div>
  {["Hello ", <span>World</span>, "!"]}
</div>

Функции могут быть так же использованы как потомки. Однако, нужно координировать их поведение с родительским компонентом.

Функция

<div>
  {() => { return "hello world!"}()}
</div>

Array as children


Использование массива потомков, это обычный паттерн, например так вы делаете списки в React.

Используйте map(), чтобы сделать массив элементов React, для каждого значения в массиве.

<ul>
  {["first", "second"].map((item) => (
    <li>{item}</li>
  ))}
</ul>

Это эквивалентно литералу массива с объектами

<ul>
  {[
    <li>first</li>,
    <li>second</li>,
  ]}
</ul>

Такой паттерн может быть использован совместно с деструктуризацией, распределением атрибутов и другими фичами, чтобы упростить написание кода

<ul>
  {arrayOfMessageObjects.map(({ id, ...message }) =>
    <Message key={id} {...message} />
  )}
</ul>

Function as children


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

<div>{() => { return "hello world!»}()}</div>

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

Эта мощная техника используется в таких библиотеках как ReactMotion. Когда вы применяете ее, логика рендера может управляйся из родительского компонента, вместо того, чтобы полностью передать ее самому компоненту.

Render callback


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

const Width = ({ children }) => children(500)

Компонент вызывает потомков, как функцию с определенным аргументом. В данном случае это число 500.

Чтобы использовать этот компонент мы передаем ему функцию как потомка.

<Width>
  {width => <div>window is {width}</div>}
</Width>

Получим такой результат

<div>window is 500</div>

При таком подходе, можно использовать параметр (width), для условного рендеринга

<Width>
  {width =>
    width > 600
      ? <div>min-width requirement met!</div>
      : null
  }
</Width>

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

const MinWidth = ({ width: minWidth, children }) =>
  <Width>
    {width =>
      width > minWidth
        ? children
        : null
    }
  </Width>

Очевидно, что статичный компонент Width, не очень полезен, но мы можем наблюдать за размерами окна браузера при таком подходе, это уже что-то

class WindowWidth extends React.Component {
  constructor() {
    super()
    this.state = { width: 0 }
  }

  componentDidMount() {
    this.setState(
      {width: window.innerWidth},
      window.addEventListener(
        "resize",
        ({ target }) =>
          this.setState({width: target.innerWidth})
      )
    )
  }

  render() {
    return this.props.children(this.state.width)
  }
}

Многие предпочитают Компоненты Высшего Порядка для такого типа функционала. Это вопрос личных преференций.

Children pass-through


Вы можете создать компонент, чтобы применить контекст и рендерить потомков.

class SomeContextProvider extends React.Component {
  getChildContext() {
    return {some: "context"}
  }

  render() {
    // how best do we return `children`?
  }
}

Тут вам следует принять решение. Обернуть потомков в еще один html тэг (div), или вернуть только потомков. Первый вариант может повлиять на существующую разметку и может нарушить стили. Второй — приведет к ошибке (вы помните, что можно вернуть только один родительский элемент из компонента)

Вариант 1: дополнительный div

return <div>{children}</div>

Вариант 2: ошибка

return children

Лучше всего управлять потомками при помощи специальных методов — React.Children. Например пример ниже позволяет вернуть только потомков и не требует дополнительной обертки

return React.Children.only(this.props.children)

Proxy component


(Не уверен, что это название вообще что-то значит) прим. автора статьи

Кнопки повсюду в приложении. И каждая из них должна иметь атрибут типа ‘button’

<button type=«button">

Писать такое сотни раз ручками — не наш метод. Мы можем написать компонент более высокого уровня, чтобы перенаправить props в компонент уровнем ниже.

const Button = props =>
  <button type="button" {…props}>

Далее вы просто используете Button, вместо button, и можете быть уверены, что нужный атрибут будет присутствовать в каждой кнопке.

<Button />
// вернет <button type="button"><button>

<Button className="CTA">Send Money</Button>
// вернет <button type="button" class="CTA">Send Money</button>

Style component


Это Proxy Component примененный к стилям. Скажем, у нас есть кнопка. Она использует классы, чтобы выглядеть как ‘primary’.

<button type="button" className="btn btn-primary»>

Можно замутить такое используя несколько простых компонентов

const PrimaryBtn = props =>
  <Btn {...props} primary />

const Btn = ({ className, primary, ...props }) =>
  <button
    type="button"
    className={classnames(
      "btn",
      primary && "btn-primary",
      className
    )}
    {...props}
  />

Это поможет визуализировать происходящее
PrimaryBtn()
↳ Btn({primary: true})
↳ Button({className: «btn btn-primary»}, type: «button»})
↳ '<button type=«button» class=«btn btn-primary»>'

Использование этих компонентов вернет одинаковый результат

<PrimaryBtn />
<Btn primary />
<button type="button" className="btn btn-primary" />

Такой подход может принести ощутимую пользу, так как изолирует определенные стили в определенном компоненте.

Event switch


При написании обработчиков событий, обычно мы используем соглашение о названии функций

handle{eventName}
handleClick(e) { /* do something */ }

Для компонентов, которые обрабатывают несколько событий, такое наименование может быть излишне повторяющемся. Сами по себе названия не дают нам никакой ценности, так как они просто направляют к действиям/функциям

handleClick() { require("./actions/doStuff")(/* action dtes */) }
handleMouseEnter() { this.setState({ hovered: true }) }
handleMouseLeave() { this.setState({ hovered: false }) }

Давайте напишем простой обработчик для всех событий с переключателем по типу события (event.type)

handleEvent({type}) {
  switch(type) {
    case "click":
      return require("./actions/doStuff")(/* action dates */)
    case "mouseenter":
      return this.setState({ hovered: true })
    case "mouseenter":
      return this.setState({ hovered: false })
    default:
      return console.warn(`No case for event type "${type}"`)
  }
}

Можно так же вызывать функции аргументы напрямую, используя функцию-стрелку

<div onClick={() => someImportedAction({ action: "DO_STUFF" })}

Не парьтесь насчет оптимизации производительности, пока не столкнулись с такими проблемами. Серьезно, не нужно.

* Лично я не считаю такой подход удачным, тк он не добавляет читаемости коду. Я предпочитаю использовать фичи React c функциями которые привязываются к контексту автоматом. То есть следующая нотация более не является необходимостью

this.handleClick = this.handleClick.bind(this)

вместо нее работает следующая нотация

handleClick = () => {…}  // вместо handleClick() {...}

и далее где-то возможно просто

onClick={this.handleClick}

В таком случае контекст (this) не будет утерян, если внутри функция обработчик ссылается к нему. Соответственно, такие функции можно легко передавать в качестве props другим компонентам и вызывать в них.

Также, в случае, если мы передаем такую функцию в потомок, Простой Компонент, то можем получить ссылку на DOM элемент этого компонента через event.target в родительском компоненте, что иногда полезно.

class SomeComponent extends React.Component {	
  onButtonClick = (e) => {
     const button = e.target;
     // …
  }
  render() {
   <div>
      <Input … />
      <Button clickHandler={this.onButtonClick} />
   </div>
  }
}

const Button = ({clickHandler, …props}) => {
  const btnClickHandler = (e) => {
    // что-то происходит
    e.preventDefault()
    clickHandler(e)
  }
  return <button onClick={btnClickHandler}/>
}

Layout component


Компоненты макета это что-то вроде статических элементов DOM. Скоро всего они не будут обновляться часто, если будут вообще.

Рассмотрим компонент который содержит два компонента горизонтально.

<HorizontalSplit
  leftSide={<SomeSmartComponent />}
  rightSide={<AnotherSmartComponent />}
/>

Мы можем агрессивно оптимизировать его работу.

Так как HorizontalSplit будет родительским компонентом для обоих компонентов он никогда не станет их владельцем. Мы можем сказать чтобы он никогда не обновлялся, при этом не прорывая жизненные циклы внутренних компонентов.

class HorizontalSplit extends React.Component {
  shouldComponentUpdate() {
    return false
  }
  render() {
    <FlexContainer>
      <div>{this.props.leftSide}</div>
      <div>{this.props.rightSide}</div>
    </FlexContainer>
  }

Container component


“A container does data fetching and then renders its corresponding sub-component. That’s it.” — Jason Bonta

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

const CommentList = ({ comments }) =>
  <ul>
    {comments.map(comment =>
      <li>{comment.body}-{comment.author}</li>
    )}
  </ul>

Мы можем создать новый компонент ответственный за получение данных и рендер компонента CommentList

class CommentListContainer extends React.Component {
  constructor() {
    super()
    this.state = { comments: [] }
  }

  componentDidMount() {
    $.ajax({
      url: "/my-comments.json",
      dataType: 'json',
      success: comments =>
        this.setState({comments: comments});
    })
  }

  render() {
    return <CommentList comments={this.state.comments} />
  }
}

Мы можем писать различные компоненты-контейнеры для разных контекстов приложения.

Higher-order component


Функция высшего порядка это функция которая может принимать в качестве аргументов другие функции и/или возвращать функции. Не более сложно чем данное определение. Так что такое компоненты высшего порядка?

Вы уже используете компоненты-контейнеры, это просто контейнеры, обернутые в функцию. Давайте начнем с простого Greeting компонента.

const Greeting = ({ name }) => {
  if (!name) { return <div>Connecting...</div> }
  return <div>Hi {name}!</div>
}

Если он получит props.name, он отрендерит данные. В противном случае он отрендерит “Connecting…”. Теперь немного более высокий порядок:

const Connect = ComposedComponent =>
  class extends React.Component {
    constructor() {
      super()
      this.state = { name: "" }
    }

    componentDidMount() {
      // this would fetch or connect to a store
      this.setState({ name: "Michael" })
    }

    render() {
      return (
        <ComposedComponent
          {...this.props}
          name={this.state.name}
        />
      )
    }
  }

Это функция которая возвращает компонент, который рендерит компонент, который мы передали в качестве аргумента (ComposedComponent)

Далее мы оборачиваем компоте в эту функцию.

const ConnectedMyComponent = Connect(Greeting)

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

Ссылки (все на английском):

Поделиться публикацией
Похожие публикации
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 26
  • +3

    Про key забыли.


    <ul>
      {["first", "second"].map((item) => (
        <li>{item}</li>
      ))}
    </ul>

    <ul>
      {[
        <li>first</li>,
        <li>second</li>,
      ]}
    </ul>

    Будет предупреждение:


    Warning: Each child in an array or iterator should have a unique "key" prop. See https://fb.me/react-warning-keys for more information.
    • –1
      да, конечно, просто тут не об этом…
    • –2
      И еще немного о Destructuring Arguments:

      const {id: someIdInData} = data
      console.log(id)
      
      • +3
        Только правильно так (имя переменной в которую попадет значение, указывается справа от двоеточия):
        const {id: someIdInData} = data
        console.log(someIdInData)
        
      • 0
        Stateless functions — очень удобная в быту штука. Но, к сожалению, пока не умеет shouldComponentUpdate для того, чтобы проверить самому props, сделать short circuit и не рендерить всех детей. А было бы классно, в некоторых случаях top-down rendering стал бы ну очень простым и дешевым.
        Но вроде бы обещают сделать.
        • –1
          Не очень понятно, что имеешь ввиду, можешь более развернутый пример привести?
          • 0
            О, ну тут всё достаточно просто.
            Что происходит, когда надо перерисовать компонент? Вызывается метод shouldComponentUpdate(nextProps, nextState): Boolean.

            Если метод вернет false, то всё дерево компонентов, которое строится в результате работы метода render() останется нетронутым — это называется short circuit. Т.е. ты как-бы говоришь реактовскому движку «спокойно парень, я уверен, ничего не изменилось», и реакт пропускает целиком все поддерево, которое растет из этого компонента.

            Если метод вернет true, то реактовский движок вызовет метод render, сверит результат и если что-то изменилось, то начнется reconciliation, который сам по себе отдельная история.

            Мораль: правильно написанный (но не всегда :) ), shouldComponentUpdate может сильно ускорить перерисовку.
            И вот этого метода в functional components нету, хотя было бы круто, если бы был.
            • 0

              тут на помощь может прийти recompose c хелпером pure:


              import pure from 'recompose/pure';
              
              function MyComponent() {
                 return <div>I am pure!</div>
              }
              
              export default class pure(MyComponent);
              • 0

                В целом — да, но в принципе такой штуки можно и достичь простой оберткой function -> react class. Но за ссылку спасибо.

                • 0

                  Может наоборот — react-class который оборачивает функцию?


                  Если нет, то можно посмотреть пример, как это делается?

        • +2
          По поводу Children pass-thru:

          Лучше всего управлять потомками при помощи специальных методов — React.Children. Например пример ниже позволяет вернуть только потомков и не требует дополнительной обертки

          return React.Children.only(this.props.children)
          


          Это лишь способ указать, что children железно должен быть одним элементом в любом случае. Иначе React бросит исключение. Это никак не возможность вернуть несколько дочерних элементов напрямую, без оборачивающего элемента. Пример выше лишь проверит, что потомок один и вернет его.
          • +9

            В статье с названием "паттерны React" всего один паттерн (stateless component) и один антипаттерн (event switch), ну за уши можно притянуть еще и "Higher-order component", что, вообще-то говоря, некое подобие карринга, а, главное, является основами JS в секции "замыкания". Остальное — либо непонимание ООП (Container component), хотя, в целом, это ближе к паттерну "провайдер" (https://en.wikipedia.org/wiki/Provider_model), либо возможности es2015+ или jsx.


            Теперь конструктивно по пунктам:


            1. Про stateless function, она же "глупый компонент", "глупое представление" и "чистая функция" (в очень вольной интерпретации) сказано про её красоту, но не сказано главное преимущество, ведь действительно, всем плевать на производительность, когда можно писать так, в пару строк, без всяких там классов. А именно — у нее есть автоматический shouldComponentUpdate, который всегда сверяет — изменились ли переданные параметры или нет, что делает использование этого синтаксиса крайне желательным и удобным, покуда позволяет повысить производительность без лишних строк кода (проверки параметров вручную), но накладывает ограничение — параметры сверяются через ===, т.е. если изменилось какое-то свойство объекта, а не сам объект (объект передался по ссылки по-прежнему), компонент не перерисуется, будете гадать потом почему. Хорошо работает в купе с immutable.


            2. JSX Spread Attributes. Object.assign для ленивых, но нужно признаться, что очень удобный функционал. Более того, он так же работает и в js, так что можно писать что-то в стиле const options = {someDefaultValue: true, anotherValue: false, ...passedOptions};. Только не забываем подключить preset: react в babel.


            3. Conditional Rendering. Зло, best practices — выносить подобные вещи в константы и определять их до функции return. Например:


              const warningMsg = hasWarning && <div>warning: {warning}</div>;
              return (<div>
              {warningMsg}
              </div>);

            4. Ну и да. ЧЕГО? Какой conditional renderig? Тут просто стандартные возможности js (еще в далеком 2007 писали var something = param.something || default) + основы JSX в виде рендера того, что находится в фигурных скобках.


            5. Children Types. Ложь, кроме как строки, Number, Boolean и React node, а так же массива из этого, (с недавних, вроде как с 0.14 версии, еще и null) ничего он рендерить не умеет. На попытку отрендерить обычный объект ругнется Error: Objects are not valid as a React child. Вдобавок, это эм документированная (но автор документацию явно не читал) и основная, как шаблонизатора, возможность JXS, давайте как паттерны может быть еще и то, что в JS можно два числа складывать напишем?


            6. Children pass-through. Опять же есть в документации и является частью библиотеки. Однако будте предельно осторожны с этой функцией, можно напороться, что он по той или иной причине не перерендерит.


            7. Event switch. Антипаттерн, имеющий целый вагон проблем. Одна из основных — IDE вам тут никак не поможет, а вместо ENUM или хотя бы констант используются строки, шанс ошибиться велик. Вторая — масштабируемость и расширяемость. Вообще задание "перепишите код с switch таким образом, чтобы его было легко изменять и расширять" — типичное тестовое задание для junior, что как бы намекает, что так лучше не делать. Ну и да, полностью ломает ООП, че уж.


            8. Layout component. Используйте в нем shouldComponentUpdate с умом и крайней осторожностью, потому что если вы захотите передавать сквозь него какие-то параметры в дочерние элементы из "умного компонента" вниз в "глупые", то из-за принудительного false в shouldComponentUpdate ничего перерисовываться не будет.


            9. Higher-order component: я уже говорил, что это карринг, а так же основы js, не понятно, по какой причине они бы не срабатывали в JSX.

            Это были замечания к автору. Замечания к переводчику: promt образца 2007 года detected. Каждое второе предложение переведено настолько странно, что если кидать в личку — исправлений наберется на вторую такую же статью.


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

            • 0

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

              • 0

                Насчёт 7. switch в javascript зло конечно дикое, но из него можно изобразить что-то вроде паттерн матчинга для бедных. Для очень бедных.


                switch(true) {
                  case type === "click" && something.isDefined() === true:
                    return "It was click";
                case type === "mouseenter" && somethingElse.isDefined() === true:
                    return "It was mouseenter";
                default:
                    return console.warn(`No case for event type "${type}"`);

                На мой взгляд даже в таком виде это сильно симпатичнее цепочки if-else-if. Но дно достигается, конечно, в момент объявления переменной в любом case. Никакие let и const не спасают — scope у всех один.

                • 0
                  Или я не понял, о каком дне вы говорите, или вы { } в case не ставили:
                  case type === "click": {
                        ...
                        return;
                  }
                  
                  • 0

                    Я вот либо что-то упустил в самых основах, либо это нечто совсем недавно появилось. Но хм… это не создает новой области видимости. Если не сложно, можно ссылку на пример? Вот gist с прямым примером: https://gist.github.com/wertlex/b97115e0f2fe0bc023297f6b2db8edd5

                    • 0
                      в ес6 (после бабеля) создаёт
                      • 0
                        У вас в примере то, о чем я говорил. Переменная value есть в обоих case и каждая из них имеет свое значение.
                        В теории, если я не ошибаюсь, должна создаваться блочная область видимости. Как браузеры делают — не знаю. Babel просто имитирует блочную видимость и в вашем примере переименует второй value в _value, чтобы имена не пересекались.
                        • 0
                          Это с es2015 пресетом полным он так поступит. Хром уже давно все это умеет без бабеля.Только плагин на импорт-экспорт нужен и все. Только хвостовую рекурсию не умеет из es2015.
                    • 0
                      А по поводу опечаток, можно собрать все event'ы, приравненные к строке и использовать их как переменные.
                      Это, кстати, recommended-practice небезызвестного Redux'a хоть и для иных строк.
                    • 0
                      Вот по п.3 когда она еще константа, а когда ее уже надо в отдельный компонент выделять есть критерии? (речь не о вновь пишущейся константе а от той что с возрастом усложняется)

                      допустим там у дива класс появился, у ворнинга свое условие и эвент еще какой?
                      • 0

                        Если это класс и подобное — нет, имеется ввиду наличие или отсутствие или выбор одного из двух элементов. Классы и прочие аттрибуты — тоже желательно считать до рендера, но местами, чтобы не загромождать, можно и инлайново. Если же весь шаблон сделать вот как рекомендует автор (инлайново в шаблоне) — он быстро разрастется и станет нечитаемым. Что касается когда нужно выносить в константу, а когда в отдельный компонент — по мне, так первым сигналом является переиспользование. Если испольуете одно и то же хотя бы в двух местах — уже выносите. Если просто говорить про объем — я не могу сказать какое-то конкретное количество строк, на усмотрение ваше

                      • 0
                        Согласен с замечаниями, некоторые из пунктов статьи действительно странные (Event switch — в первую очередь).
                        Остальное пожалуй больше для начинающих, кто в 2007 про var something = param.something || default ничего знал.
                      • 0
                        Надеюсь jquery ajax здесь только для примера?
                        • 0

                          JSX Spread Attributes имеет одну проблему, в дочерний компонент может залететь то, что не нужно. И начиная с 15 версии Реакт начинает ругаться на атрибуты, которые не были указаны в PropTypes

                          • 0
                            А как быть с HOC? Он по определению не знает, что нужно дочернему компоненту в общем случае, если и использует собственные атрибуты, то все остальные должен передать как есть.

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