Студент здесь, пытается создать приложение для своей диссертации, используя Laravel, React и Inertia.
Я пытаюсь создать простой компонент Combobox многократного использования. Он должен иметь HTML-атрибут id и содержать идентификатор в качестве значения, чтобы я мог использовать и то, и другое в контроллере Laravel.
Вот что у меня есть. Проблема в том, что большинство строк функции handleSelect не работают. (С пометкой «не бывает».)
Когда пользователь выбирает элемент из ul, я ожидаю:
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>
@Дэвид - я обновил свой пост по просьбе. Как видите, никакой (пользовательский) CSS не применяется. Кроме того, похоже, что выполняется часть функции handleSelect. Я уточнил свой пост, чтобы отразить это.
Похоже, onBlur = {() => {setShowUl(false)}}
скрывает <ul>
до того, как клик будет обработан. Вероятно, вы не захотите скрывать его, если пользователь нажмет на него.
Попробуй это
onClick = {() => this.handleSelect(item.name, item.id)}
или
onClick = {handleSelect(item.name, item.id)}
Можете ли вы рассказать, почему ОП должен «попробовать это»? В чем заключалась проблема в исходном коде и как любое из этих изменений решает эту проблему? В последнем случае изменение handleSelect
будет выполняться сразу после рендеринга компонента, а не при возникновении click
.
Проблема в том, что большинство строк функции 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)
. Прочитав ваш ответ, я попробую прослушиватель по щелчку мыши. Спасибо!
Если все в функции «не происходит», то это убедительно свидетельствует о том, что функция просто не вызывается. Может быть, какая-то проблема со стилем скрывает его, и элемент фактически не получает событие щелчка? Может быть, что-то еще не работает до того, как событие щелчка будет обработано? Можете ли вы обновить это до минимально воспроизводимого примера в виде фрагмента кода React, который демонстрирует проблему?