React: создание поля со списком

Студент здесь, пытается создать приложение для своей диссертации, используя Laravel, React и Inertia.

Я пытаюсь создать простой компонент Combobox многократного использования. Он должен иметь HTML-атрибут id и содержать идентификатор в качестве значения, чтобы я мог использовать и то, и другое в контроллере Laravel.

Вот что у меня есть. Проблема в том, что большинство строк функции handleSelect не работают. (С пометкой «не бывает».)

Когда пользователь выбирает элемент из ul, я ожидаю:

  • видимый ввод {title}_input, содержащий item.name ->, не происходит
  • скрытый {title}_id, содержащий item.id ->, не происходит
  • ул, которую нужно закрыть -> БЫВАЕТ

const {useState} = React;

const Combobox = ({}) => {
    const [input, setInput] = useState('')
    const [returnValue, setReturnValue] = useState ('')
    const [showUl, setShowUl] = useState(false)

    //TURN INTO PROPS
        const title = 'test'
        const array = [
            { id: 1, name: 'eins' },
            { id: 2, name: 'zwei' },
            { id: 3, name: 'polizei' },
        ]
    //end of props

    const filteredArray = (
        input
        ? array.filter(item => item.name.toLowerCase().includes(input.toLowerCase()))
        : array
    )

    const handleSelect = (name, id) => {
        setInput(name) // does not happen.
        setReturnValue(id) // does not happen.
        setShowUl(false)
        console.info(`input is now ${input}`) // does not happen.
    }

    return (
        <div>
            <input
                id = {`${title}_input`}
                type = "text"
                placeholder='choose an option'
                value = {input}
                onChange = {e => {setInput(e.target.value)}}
                onFocus = {() => {setShowUl(true)}}
                onBlur = {() => {setShowUl(false)}}
            />
            <input
                id = {`${title}_id`}
                type = "hidden"
                value = {returnValue}
            />
            {showUl &&
                <ul>
                    {filteredArray.map(item => (
                        <li
                            key = {item.id}
                            onClick = {() => handleSelect(item.name, item.id)}
                        >{item.name}</li>
                    ))}
                </ul>
            }
        </div>
    )
}

ReactDOM.createRoot(
    document.getElementById("root")
).render(
    <Combobox/>
);
<div id = "root"></div>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>

Если все в функции «не происходит», то это убедительно свидетельствует о том, что функция просто не вызывается. Может быть, какая-то проблема со стилем скрывает его, и элемент фактически не получает событие щелчка? Может быть, что-то еще не работает до того, как событие щелчка будет обработано? Можете ли вы обновить это до минимально воспроизводимого примера в виде фрагмента кода React, который демонстрирует проблему?

David 06.05.2024 17:31

@Дэвид - я обновил свой пост по просьбе. Как видите, никакой (пользовательский) CSS не применяется. Кроме того, похоже, что выполняется часть функции handleSelect. Я уточнил свой пост, чтобы отразить это.

Bart 06.05.2024 18:36

Похоже, onBlur = {() => {setShowUl(false)}} скрывает <ul> до того, как клик будет обработан. Вероятно, вы не захотите скрывать его, если пользователь нажмет на него.

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

Ответы 2

Попробуй это

 onClick = {() => this.handleSelect(item.name, item.id)}

или

onClick = {handleSelect(item.name, item.id)}



   

Можете ли вы рассказать, почему ОП должен «попробовать это»? В чем заключалась проблема в исходном коде и как любое из этих изменений решает эту проблему? В последнем случае изменение handleSelect будет выполняться сразу после рендеринга компонента, а не при возникновении click.

David 06.05.2024 18:17
Ответ принят как подходящий

Проблема в том, что большинство строк функции handleSelect не работают.

Функция не вызывается. Так что на самом деле это все строки кода в этой функции, и дело не в том, что они «не работают», а в том, что они просто не вызываются вообще.

Это событие происходит первым:

onBlur = {() => {setShowUl(false)}}

Фактически это означает повторный рендеринг компонента до того, как событие click будет обработано. Удалите его, и событие click заработает как положено:

const {useState} = React;

const Combobox = ({}) => {
    const [input, setInput] = useState('')
    const [returnValue, setReturnValue] = useState ('')
    const [showUl, setShowUl] = useState(false)

    //TURN INTO PROPS
        const title = 'test'
        const array = [
            { id: 1, name: 'eins' },
            { id: 2, name: 'zwei' },
            { id: 3, name: 'polizei' },
        ]
    //end of props

    const filteredArray = (
        input
        ? array.filter(item => item.name.toLowerCase().includes(input.toLowerCase()))
        : array
    )

    const handleSelect = (name, id) => {
        setInput(name) // does not happen.
        setReturnValue(id) // does not happen.
        setShowUl(false)
        console.info(`input is now ${input}`) // does not happen.
    }

    return (
        <div>
            <input
                id = {`${title}_input`}
                type = "text"
                placeholder='choose an option'
                value = {input}
                onChange = {e => {setInput(e.target.value)}}
                onFocus = {() => {setShowUl(true)}}
            />
            <input
                id = {`${title}_id`}
                type = "hidden"
                value = {returnValue}
            />
            {showUl &&
                <ul>
                    {filteredArray.map(item => (
                        <li
                            key = {item.id}
                            onClick = {() => handleSelect(item.name, item.id)}
                        >{item.name}</li>
                    ))}
                </ul>
            }
        </div>
    )
}

ReactDOM.createRoot(
    document.getElementById("root")
).render(
    <Combobox/>
);
<div id = "root"></div>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>

Скрыть меню — это немного сложнее, чем просто событие onBlur для элемента <input>. Такой инструмент, как этот может быть тем, что вы ищете, или, возможно, создайте свой собственный. Но по сути вам нужно скрыть <ul> при нажатии в любом месте, кроме <input> или <ul>.

Это абсолютно правильно. Судя по вашему последнему комментарию к моему сообщению, я исправил проблему, добавив тайм-аут: setTimeout(() => {setShowUl(false)}, 800). Прочитав ваш ответ, я попробую прослушиватель по щелчку мыши. Спасибо!

Bart 07.05.2024 09:59

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