На выходных я работал над проектом, в котором мне нужно было передать дочерний компонент дочернему, но при выборе сделать его родительским. Я наткнулся на множество образцов, но ни один из них не был аккуратным!.
Некоторые использовали ref (что тоже неплохо), а некоторые манипулировали DOM с помощью document.querySelector и т. д. Так что я решил написать об этом, Путь React!
Итак, подумайте о случае использования вкладок, когда у вас есть компонент вкладок, и при нажатии на вкладку вы хотите показать ее содержимое. Если вы исходите из фона jQuery, то вы, должно быть, думаете, что я должен создать столько элементов, а затем показать скрытие на основе выбора → Верно?
Следующий рисунок должен иллюстрировать вариант использования:
Но в React мыслительный процесс должен быть таким:
- Родительский компонент (Tabs.jsx)
- Дочерний компонент (Tab.jsx)
Parent(Tabs) будет просто обертывать дочерний компонент и позаботится об изменении вкладок и т. д., в то время как дочерний компонент будет представлять отдельные вкладки (Tab1, Tab2, Tab3 и т. д.). Теперь, где будет раздел контента? и где должно быть объявление этого содержания? Возьмите следующее использование этих компонентов:
<Tabs> <Tab id="1" title="Tab 1"> This is content for tab 1 </Tab> <Tab id="2" title="Tab 2"> This is content for tab 2 </Tab> <Tab id="3" title="Tab 3"> This is content for tab 3 </Tab> </Tabs>
Объявление имеет смысл, потому что каждая вкладка должна иметь свои дочерние компоненты, верно? но это создает некоторую сложность, как это будет отображать дочерние элементы в разделе контента, который находится в Parent (Tabs.jsx)?
Взгляните на реализацию Tabs.jsx. Пара важных вещей здесь
- Как родительский компонент, он имеет как вкладки, так и разделы содержимого.
- Вы можете получить доступ к дочерним компонентам, используя
this.props.children
- Перед визуализацией дочерних элементов мы хотим добавить некоторые новые свойства
onChange
- Вы не можете напрямую изменить
this.props.children
, поэтому мы будем использовать React.cloneElement.
import React, { Component } from 'react'; class Tabs extends Component { constructor(props) { super(props); this.state = { content: "" } } handleChange= (event) => { this.setState({ content: event }); } render() { return(<div className="tab-container"> <ul> {React.Children.map(this.props.children, child => { return React.cloneElement(child, {onChange: this.handleChange}); })} </ul> <div className="content-container"> {this.state.content} </div> </div>); } } export default Tabs;
Теперь у нас есть родительский элемент, который содержит раздел content, а также элементы Tab. И перед вызовом дочерних компонентов мы добавили наш обработчик onChange, чтобы мы могли прослушивать изменения и реагировать!
Напишем Tab (дочерний) компонент:
import React, {Component} from 'react' class Tab extends Component { handleClick = (event) => { this.props.onChange(this.props.children); } render() { return(<li key={this.props.id} data-id={this.props.id} onClick={this.handleClick}> {this.props.title} </li>); } } export default Tab;
Вау! это просто не так ли? Итак, что мы здесь делаем? Мы говорим визуализировать элемент <li>
(пока не визуализировать дочерние элементы), и когда кто-то нажимает на него, передаем дочерние элементы родительскому обработчику.
Теперь, если вы внимательно посмотрите на родительский компонент, то увидите, что мы что-то делаем там с состоянием.
handleChange= (event) => { this.setState({ content: event }); }
И в методе рендеринга мы визуализируем дочерние компоненты, такие как:
<div className="content-container"> {this.state.content} </div>
Вы, должно быть, думаете, что вообще происходит?
Давайте посмотрим на это под другим углом… это довольно просто. В рамках объявления мы объявили содержимое вкладки своим дочерним элементом, и когда пользователь нажмет на вкладку, он отправит эти дочерние элементы родительскому компоненту, а Parent установит состояние для их отображения. Простой!
Я создал рабочий codepen для лучшего понимания! Надеюсь, это поможет!