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

Некоторые использовали ref (что тоже неплохо), а некоторые манипулировали DOM с помощью document.querySelector и т. д. Так что я решил написать об этом, Путь React!

Итак, подумайте о случае использования вкладок, когда у вас есть компонент вкладок, и при нажатии на вкладку вы хотите показать ее содержимое. Если вы исходите из фона jQuery, то вы, должно быть, думаете, что я должен создать столько элементов, а затем показать скрытие на основе выбора → Верно?

Следующий рисунок должен иллюстрировать вариант использования:

Но в React мыслительный процесс должен быть таким:

  1. Родительский компонент (Tabs.jsx)
  2. Дочерний компонент (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. Пара важных вещей здесь

  1. Как родительский компонент, он имеет как вкладки, так и разделы содержимого.
  2. Вы можете получить доступ к дочерним компонентам, используя this.props.children
  3. Перед визуализацией дочерних элементов мы хотим добавить некоторые новые свойства onChange
  4. Вы не можете напрямую изменить 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 для лучшего понимания! Надеюсь, это поможет!