Что такое реквизит для рендеринга? Согласно официальному определению реакции:
относится к технике совместного использования кода между компонентами React с использованием реквизита, значением которого является функция.
Другими словами, компоненты родительского компонента или компонента-контейнера могут получить доступ к состояниям или функциям дочернего компонента без необходимости передавать туда и обратно реквизиты.
Это очень полезно, когда мы знаем, что есть компонент с рекурсивной или итеративной логикой, который нужно использовать в нескольких местах.
Итак, как мы можем инкапсулировать это поведение, чтобы мы могли легко поделиться им с родительскими компонентами?
Давайте попробуем выполнить рефакторинг от шаблона State Hoisting к шаблону Render Props.
(«поднятие состояния» осуществляется путем передачи обратного вызова из компонента-контейнера в дочерний компонент.)
Пример 1
Допустим, есть компонент Input, который получает обратный вызов от компонента InputContainer и вызывает события. С помощью обратного вызова состояние поднимается в контейнер, в котором оно обновляет локальное состояние.
const Input = ({ onChange }) => ( <input onChange={e => onChange(e.target.value)} /> ); class InputContainer extends Component { state = { name: "" }; render() { return ( <> <Input onChange={newName => this.setState({ name: newName })} /> <p>{this.state.name}</p> </> ); } }
— — — коды рефакторинга для Render Props ›››
class Input extends Component { state = { name: 'Alice', } render() { return ( <> <input onChange={e => this.setState({ name: e.target.value})} / {this.props.render(this.state)} </> ); } } function InputContainer() { return <Input render={({ name }) => <p>{name}</p>} /> }
Здесь произошло то, что состояние теперь контролируется внутри Input, а не с помощью InputContainer. Но InputContainer по-прежнему может получить доступ к состоянию с реквизитами рендеринга.
Это не выглядит впечатляюще. пока что. Но всякий раз, когда вы хотите использовать компонент ввода в другом месте, вам больше не нужно повторять такие коды, как this.setState… больше!
Вы также можете преобразовать коды в шаблон FaaC (Function-as-a-Child).
— — — коды рефакторинга для Render Props (шаблон FaaC)›››
class Input extends Component { state = { name: 'Alice', } render() { return ( <> <input onChange={e => this.setState({ name: e.target.value})} / {this.props.children(this.state)} </> ); } } function InputContainer() { return <Input>{({ name }) => <p>{name}</p>}</Input> }
Это в конечном счете одно и то же. Но лично шаблон FaaC выглядит намного чище.
Пример 2
Вы также можете отправить функцию в качестве реквизита рендеринга. Это также очень полезно в случае, когда вам не нужно знать состояние потребителя, а нужно знать только функцию, контролирующую состояние.
Например, здесь у нас есть модальный компонент, и мы хотим управлять состоянием isVisible из родителя, но нам не обязательно это состояние.
function ModalContainer(){ return( <Modal> {({ showModal }) => ( <CloseButton onClick={(e) => { e.stopPropagation(); e.preventDefault(); showModal(); }} /> )} </Modal> ) } class Modal extends Component { state = { visible: false }; showModal = () => { this.setState({ visible: true }) }; hideModal = () => { this.setState({ visible: false }) }; render() { const { visible } = this.state; return ( <> <div className={classnames('Modal', { 'Modal-visible': visible })}> ....{modal content} <Button handleClick={this.hideModal}> Cancel </Button> </div> {children({ showModal: this.showModal })} </> ); }
Плюсы и минусы
Плюсы!
- Это очень полезно, когда мы знаем, что есть компонент с рекурсивной или итеративной логикой, потому что мы можем инкапсулировать его в 1 компонент и читать из разных мест.
- очень ясно, какой компонент вызывается, и состояние изолировано.
- никаких коллизий имен, как у вас будет с HOC
Недостатки:
- не так аккуратно в JSX, так как его нужно обернуть выражением.
- поскольку его нужно обернуть, вы не можете использовать реквизиты рендеринга, когда хотите, чтобы контейнер и потребитель находились в двух разных местах.
Использованная литература:
https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce
Реквизиты рендеринга — React
Термин «реквизит рендеринга относится к методу совместного использования кода между компонентами React с использованием реквизита, значением которого является…reactjs.org »