Скрыть компонент React без размонтирования

#reactjs

#reactjs

Вопрос:

Я пытаюсь эффективно создать представление с вкладками, в котором содержимое каждой вкладки извлекается только при нажатии на вкладку. Я реализовал это, используя набор кнопок в качестве заголовков, которые обновляют currentTab значение в состоянии контейнера, и переключатель, который отображает компонент только на основе этого currentTab значения. Затем я извлекаю данные из componentDidMount функции, достигая своего намерения загрузки, когда вкладка фактически выбрана.

Проблема в том, что я не хочу загружать данные каждый раз при выборе вкладки. Только в первый раз. Я хочу, чтобы данные в этих компонентах оставались, когда я нажимаю назад, чтобы их не нужно было извлекать снова. Я уже пытался сохранить ссылки на каждый компонент tab в компоненте контейнера и повторно использовать их, но это не сработало. Это выглядело примерно так:

 class MyContainer extends React.Component{
    constructor(props){
        super(props);
        this.state = {activeTab: this.props.initialTab}
        this.tabs = {
            'Actions': null,
            'Drawsheet': null,
            'Players': null,
            'About': null,
            'Contact': null
        };
    }

    getTab(){
        const tab = this.state.activeTab;
        if(this.tabs[tab] != null){
            return this.tabs[tab];
        }
        else {
            let newTab;
            switch (tab){
                case 'Actions':
                    newTab = <ActionsTab user={this.props.user}/>;
                    break;
                case 'Drawsheet':
                    newTab = <DrawsheetTab event={this.props.event}/>;
                    break;
                case 'Players':
                    newTab = <PlayersTab event={this.props.event}/>;
                    break;
                case 'About':
                    newTab = <AboutTab event={this.props.event}/>;
                    break;
                case 'Contact':
                    newTab = <ContactTab event={this.props.event}/>;
                    break;
            }
            this.tabs[tab] = newTab;
            return newTab;
        }
    }
    render(){
        let content = this.getTab();
        return(content);
}
  

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

Каков наилучший способ для меня скрыть уже созданные вкладки без их размонтирования? Очевидно, что недостаточно сохранять ссылки, пока они не отображаются, я предполагаю, что мне нужно отобразить их все, но просто использовать display: none или что-то в этом роде? Однако я читал в других сообщениях, что приведет к его повторному монтированию, и использование visibility заставит их по-прежнему занимать место, пока они скрыты, что также неприемлемо.

Ответ №1:

В итоге я придумал свое собственное решение, основанное на ответе @Diceros. Публикация для всех, кто натыкается на эту тему.

Я добавил tabData массив в состояние контейнера, а затем создал saveTabData функцию, которую я передал каждому компоненту как onLoadData и передал сами данные компоненту.

В каждом компоненте tab вместо вызова this.setState для сохранения данных из выборки я вызываю обратный this.props.onLoadData вызов для сохранения данных в массив containers tabData . Затем я переработал методы рендеринга каждого компонента, чтобы получать данные из this.props вместо this.state и просто отображать «Загрузка …», когда данные реквизита равны нулю (т. Е. когда он еще не загружен).

Ответ №2:

Во-первых, я бы переместил весь переключатель с компонентами вкладок в рендеринг, а затем я бы использовал componentDidUpdate и проверил, была ли изменена активная вкладка, и если да, сохраните новую вкладку в какой-то коллекции в состоянии (ниже я использовал opennedTabs ), где вы будете собирать всеиз ранее открытых вкладок, и если вкладка еще не была открыта, извлеките данные. Если он был ранее открыт, не извлекайте данные снова. Используя этот способ, вам не нужно заботиться о рендеринге и размонтировании вкладок и просто правильно обрабатывать данные.

В коде:

 componentDidUpdate() {
    let opennedTabs = [...this.state.opennedTabs];
    if (prevState.activeTab !== this.state.activeTab) {
        if (opennedTabs?.length > 0 amp;amp; !opennedTabs.includes(this.state.activeTab)) {
            //Fetch the data for this.state.activeTab
            opennedTabs.push(activeTab);
            this.setState({ opennedTabs });
        }
    }
}

render() {
            switch (this.state.activeTab){
                    case 'Actions':
                        return <ActionsTab fetchedData={dataActionsTab} user={this.props.user}/>;
                    case 'Drawsheet':
                        return <DrawsheetTab fetchedData={dataDrawsheetTab} event={this.props.event}/>;
                    case 'Players':
                        return <PlayersTab fetchedData={dataPlayersTab} event={this.props.event}/>;
                    case 'About':
                        return <AboutTab fetchedData={dataAboutTab} event={this.props.event}/>;
                    case 'Contact':
                        return <ContactTab fetchedData={dataContactTab} event={this.props.event}/>;
}
  

Комментарии:

1. opennedTabs.push(activeTab); Откуда берется эта переменная activeTab? Это должен быть сам компонент или строковый ключ? Если компонент, где я должен его хранить и устанавливать?

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