Многоразовый выпадающий список с React Hooks

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

//navigation.js
import {DropdownToggler} from './dropdown.js';
export class ErrorTriangle extends Component {
   render(){
     return(
        {DropdownToggler({uiElement: {
            toggler: <img src = {MyImg}/>,
            field: <div className = {'errorMessage'}>
                       <p>Dropdown content</p>
                   </div >
        }})
       }
     )
   }
}

//dropdown.js
import React, {useEffect, useRef, useState} from "react";
import {store} from "../api/redux/store";

const DropdownToggler = (props) => {
    const myRef = useRef(null);
    const [showField, setShow] = useState(false);
    const isMobile = store.getState().isMobile;

   const remove = (e) => {
    e.stopPropagation();

    if (myRef && myRef.current.contains(e.target)) {
        return
    }
    setShow(false);
    if (isMobile===true) {
        document.removeEventListener('touchend', remove, false)
    } else {
        document.removeEventListener('mouseup', remove, false)
    }
};

const show = (e) => {
    e.stopPropagation();
    if (showField) {
        return
    }
    setShow(true);
    if (isMobile===true) {
        document.addEventListener('touchend', remove, false)
    } else {
        document.addEventListener('mouseup', remove, false)
    }
};

return (
    <>
        {React.cloneElement(props.uiElement.toggler, {
            onTouchEnd: (e) => show(e),
            onMouseUp: isMobile ? null : (e) => show(e)
        })}

        {showField ? React.cloneElement(props.uiElement.field, {ref: node => myRef.current= node}) : null}
    </>
)
};
export {DropdownToggler};

И получите ошибку: Хуки можно вызывать только внутри тела функционального компонента. Я уже проверил существующую информацию об этой проблеме:

  1. версия реактивного горячего загрузчика 4.8.0
  2. Моя реакция и реакция-дом имеют ту же версию 16.8.4;
  3. Моя конфигурация babel содержит:

    'use strict';
    
    module.exports = {
       presets: ['@babel/preset-env', '@babel/preset-react'],
       plugins: ["@babel/plugin-proposal-class-properties", "jsx-control-statements", "react-hot-loader/babel"],
    };
    

Возможно проблема в том, что я нарушаю правила хуков https://reactjs.org/warnings/invalid-hook-call-warning.html. Буду признателен за подробные объяснения (примеры) или идеи, почему это не работает.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
3
0
4 545
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Изменять

export class ErrorTriangle extends Component {
   render(){
     return(
        {DropdownToggler({uiElement: {
            toggler: <img src = {MyImg}/>,
            field: <div className = {'errorMessage'}>
                       <p>Dropdown content</p>
                   </div >
        }})
       }
     )
   }
}

К

export function ErrorTriangle (props) {
     return(
        {DropdownToggler({uiElement: {
            toggler: <img src = {MyImg}/>,
            field: <div className = {'errorMessage'}>
                       <p>Dropdown content</p>
                   </div >
        }})
       }
     )
}

ИЛИ

Изменять

{DropdownToggler({uiElement: {
            toggler: <img src = {MyImg}/>,
            field: <div className = {'errorMessage'}>
                       <p>Dropdown content</p>
                   </div >
        }})
       }

К

{<DropdownToggler uiElement = {{
    toggler: <img src = {MyImg}/>,
    field: <div className = {'errorMessage'}>
                <p>Dropdown content</p>
            </div >
  }}/>
}

Объяснение

Проще говоря, если вы используете класс, вы должны вызывать функцию компонента так, а не как обычную функцию <Component />, или вы можете перейти от использования класса к использованию функции компонента.

@ip оба вышеуказанных решения должны работать. Если ничего не работает, скажите мне об этом

evgeni fotia 08.03.2019 16:21

Я знал о первом предложении, но оно не соответствовало моим потребностям. Второй вариант - отлично работает! Спасибо!

IP_ 12.03.2019 19:22

Другие вопросы по теме