кодесурса
«Реагировать

Render Реквизит

script1adsense2code
script1adsense3code

Термин «рендер проп» относится к технике совместного использования кода между компонентами React с использованием реквизита, значение которого является функцией.

Компонент с реквизитом рендеринга берет функцию, которая возвращает элемент React, и вызывает его вместо реализации собственной логики рендеринга.

<DataProvider render= {data => (
  <h1>Hello {data.target} </h1>
)}/>

Библиотеки, которые используют реквизит рендеринга, включают React Router и Downshift.

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

Используйте Render Реквизит для сквозных задач

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

Например, следующий компонент отслеживает положение мыши в веб-приложении:

class MouseTracker extends React.Component {
  constructor(props) {
    super(props);
    this.handleMouseMove = this.handleMouseMove.bind(this);
    this.state = { x: 0, y: 0 };
  }
  handleMouseMove(event) {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }
  render() {
    return (
      <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
        <h1>Move the mouse around!</h1>
        <p>The current mouse position is ({this.state.x}, {this.state.y})</p>
      </div>
    );
  }
}

Когда курсор перемещается по экрану, компонент отображает свои координаты (x, y) в виде <p>.

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

Поскольку компоненты являются основной единицей повторного использования кода в React, давайте попробуем немного реорганизовать код, чтобы использовать компонент <Mouse>, который инкапсулирует поведение, которое нам необходимо повторно использовать в другом месте.

// The <Mouse> component encapsulates the behavior we need...
class Mouse extends React.Component {
  constructor(props) {
    super(props);
    this.handleMouseMove = this.handleMouseMove.bind(this);
    this.state = { x: 0, y: 0 };
  }
  handleMouseMove(event) {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }
  render() {
    return (
      <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
        {/* ...but how do we render something other than a <p>? */}
        <p>The current mouse position is ({this.state.x}, {this.state.y})</p>
      </div>
    );
  }
}
class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        <Mouse />
      </div>
    );
  }
}

Теперь компонент <Mouse> инкапсулирует все поведение, связанное с прослушиванием событий mousemove и сохранением позиции (x, y) курсора, но он пока еще не может быть повторно использован.

Например, допустим, у нас есть компонент <Cat>, который отображает изображение кошки, преследующей мышь по экрану. Мы можем использовать опору <Cat mouse = {{x, y}}>, чтобы сообщить компоненту координаты мыши, чтобы он знал, где расположить изображение на экране.

В качестве первого прохода вы можете попробовать визуализировать <Cat> внутри метода render <Mouse>, например:

class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
    );
  }
}
class MouseWithCat extends React.Component {
  constructor(props) {
    super(props);
    this.handleMouseMove = this.handleMouseMove.bind(this);
    this.state = { x: 0, y: 0 };
  }
  handleMouseMove(event) {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }
  render() {
    return (
      <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
        {/*
          We could just swap out the <p> for a <Cat> here ... but then
          we would need to create a separate <MouseWithSomethingElse>
          component every time we need to use it, so <MouseWithCat>
          isn't really reusable yet.
        */}
        <Cat mouse={this.state} />
      </div>
    );
  }
}
class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        <MouseWithCat />
      </div>
    );
  }
}

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

Вот здесь и возникает реквизит рендеринга: вместо жесткого кодирования <Cat> внутри компонента <Mouse> и эффективного изменения его рендеринга, мы можем предоставить <Mouse> функцию prop, которую он использует для динамического определения того, что визуализировать -поддержка

class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
    );
  }
}
class Mouse extends React.Component {
  constructor(props) {
    super(props);
    this.handleMouseMove = this.handleMouseMove.bind(this);
    this.state = { x: 0, y: 0 };
  }
  handleMouseMove(event) {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }
  render() {
    return (
      <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
        {/*
          Instead of providing a static representation of what <Mouse> renders,
          use the `render` prop to dynamically determine what to render.
        */}
        {this.props.render(this.state)}
      </div>
    );
  }
}
class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        <Mouse render={mouse => (
          <Cat mouse={mouse} />
        )}/>
      </div>
    );
  }
}

Теперь вместо эффективного клонирования компонента <Mouse> и жесткого кодирования чего-то еще в его методе рендеринга для решения для конкретного случая использования мы предоставляем реквизит рендеринга, который <Mouse> может использовать для динамического определения того, что он рендерит.

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

Эта техника делает поведение, которое нам необходимо использовать, чрезвычайно переносимым. Чтобы получить такое поведение, визуализируйте <Mouse> с реквизитом рендера, который сообщает ему, что нужно визуализировать с текущим (x, y) курсором.

Что касается рендеринга реквизита, следует отметить одну интересную вещь: вы можете реализовать большинство компонентов высшего порядка (HOC), используя обычный компонент с опорой рендеринга. Например, если вы предпочитаете иметь компонент withMouse HOC вместо компонента <Mouse>, вы можете легко создать его, используя обычный <Mouse> с пропеллером рендеринга:

// If you really want a HOC for some reason, you can easily
// create one using a regular component with a render prop!
function withMouse(Component) {
  return class extends React.Component {
    render() {
      return (
        <Mouse render={mouse => (
          <Component {...this.props} mouse={mouse} />
        )}/>
      );
    }
  }
}

Таким образом, использование рендера позволяет использовать любой шаблон.

Использование реквизита, отличного от рендеринга

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

Хотя в приведенных выше примерах используется render, мы могли бы с таким же успехом использовать дочернюю опору!

<Mouse children={mouse => (
  <p>The mouse position is {mouse.x}, {mouse.y}</p>
)}/>
And remember, the children prop doesn?t actually need to be named in the list of ?attributes? in your JSX element. Instead, you can put it directly inside the element!
<Mouse>
  {mouse => (
    <p>The mouse position is {mouse.x}, {mouse.y}</p>
  )}
</Mouse>

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

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

Mouse.propTypes = {
  children: PropTypes.func.isRequired
};

Предостережения

Будьте осторожны при использовании Render Props с React.PureComponent

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

Например, если продолжить с нашего компонента <Mouse> сверху, если Mouse будет расширять React.PureComponent вместо React.Component, наш пример будет выглядеть следующим образом:

class Mouse extends React.PureComponent {
  // Same implementation as above...
}
class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        {/*
          This is bad! The value of the `render` prop will
          be different on each render.
        */}
        <Mouse render={mouse => (
          <Cat mouse={mouse} />
        )}/>
      </div>
    );
  }
}

В этом примере каждый раз, когда <MouseTracker> рендерит, он генерирует новую функцию в качестве значения реквизита <Mouserender>, тем самым сводя на нет эффект <Mouse>, расширяющий React.PureComponent в первую очередь!

Чтобы обойти эту проблему, вы можете иногда определить опору как метод экземпляра, например так:

class MouseTracker extends React.Component {
  // Defined as an instance method, `this.renderTheCat` always
  // refers to *same* function when we use it in render
  renderTheCat(mouse) {
    return <Cat mouse={mouse} />;
  }
  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        <Mouse render={this.renderTheCat} />
      </div>
    );
  }
}

В случаях, когда вы не можете определить опору статически (например, из-за того, что вам необходимо закрыть опоры и / или состояние компонента), <Mouse> должен вместо этого расширить React.Component.

Новый контент: Composer: менеджер зависимостей для PHP , R программирования


script1adsense4code
script1adsense5code
disqus2code
script1adsense6code
script1adsense7code
script1adsense8code
buysellads2code