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

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

Давайте погрузимся в код

Предполагая, что у вас запущено приложение React, все, что вам нужно сделать, это:
yarn add recompose
и все готово.

Государственный провайдер

Это очень простая реализация вспомогательного компонента, который предоставляет вам 2 значения; state и setState.

Полный StateProvider.js выглядит следующим образом:

import { withState } from ‘recompose’
const StateProvider = withState(
 ‘state’,
 ‘setState’,
 props => props.initialState
)(({ children, state, setState }) => children(state, setState))
export default StateProvider

Это все. Обратите внимание, что здесь нет кода React. То, что мы делаем, - это использование компонента перекомпоновки withState более высокого порядка, чтобы обернуть функцию, которая передает 2 основных параметра (состояние и setState) в children и возвращает его.

Теперь мы можем использовать это так:

<StateProvider initialState={1}>
  {(counter, setCounter) => (
    <Fragment>
      <h2>{counter}</h2>
      <button onClick={() => setCounter(counter + 1}>
       Increment
      </button>
    </Fragment>
  )}
</StateProvider>

Поскольку setState и state - это просто переданные параметры, мы можем назвать их по своему усмотрению, в данном случае это counter и setCounter. Однако initialState нужно называть так же, поскольку это опора.

initialState может иметь любое значение, которое вы поместили в обычный this.state, обычно это объект, но также массив или примитивное значение.

Переключать

Мы также можем создать что-то подобное, например, многоразовый компонент Toggle:

import { withStateHandlers } from 'recompose'
export default withStateHandlers(
  ({ initial }) => ({
    isToggled: !!initial
  }),
  {
    toggle: ({ isToggled }) => () => ({ isToggled: !isToggled })
  }
)(({ children, isToggled, toggle }) => children(isToggled, toggle))

Что можно использовать следующим образом:

<Toggle initial={false}>
  {(isOn, toggle) => (
    <Fragment>
      <input type="checkbox" checked={isOn} onClick={toggle} />
      {isOn && <p>Show when checked ^</p>}
    </Fragment>
   )}
</Toggle>

Форма (он же Formik wannabe)

Компонент формы, имеющий API-интерфейс, аналогичный классной библиотеке Formik, хотя эта реализация намного проще.

export const Form = withStateHandlers(
  ({ initialValues }) => ({ values: initialValues }),
  {
    handleChange: ({ values }) => e => ({
      values: { ...values, [e.target.name]: e.target.value }
    }),
    handleSubmit: ({ values }, { onSubmit }) => () => {
      onSubmit(values) // call onSubmit prop with values
      return { values: {} } // clear form
    }
  }
)(({ children, values, handleChange, handleSubmit }) =>
  children(values, handleChange, handleSubmit)
)

Использование:

<Form
  initialValues={{ firstName: 'John', lastName: 'Doe' }}
  onSubmit={values => console.log(values)}
>
  {(values, handleChange, handleSubmit) => (
    <div>
      <input
        name="firstName"
        onChange={handleChange}
        value={values.firstName}
      />
      <input
        name="lastName"
        onChange={handleChange}
        value={values.lastName}
      />
      <button type="submit" onClick={handleSubmit}>
        Submit
      </button>
    </div>
  )}
</Form>

Перед закрытием

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

И спасибо, что нашли время прочитать мою первую статью!