#reactjs
Вопрос:
Я в основном пытаюсь обновить фильтр элементов из массива «Все местоположения» в массив «Выпадающее местоположение», но он обновляется неправильно. при первом изменении в поле ввода он неправильно обновляет массив, а при втором изменении он его не обновляет.
import logo from "./logo.svg";
import "./App.css";
import { useState, useEffect } from "react";
function App() {
// location entered by the user
const [location, setlocation] = useState("");
const [allLocations, setallLocations] = useState(["F-1", "F-2", "G-1", "G-2"]);
const [dropDownLocations, setdropDownLocations] = useState([]);
const filterLocations = (userInput) => {
console.log("user input ", location);
allLocations.map((i) => {
if (i.includes(location)) {
console.log("true at ", i);
setdropDownLocations([...dropDownLocations, i]);
} else {
setdropDownLocations([]);
}
});
console.log("after map ", dropDownLocations);
};
return (
<div className="App">
<div>
<input
value={location}
onChange={(e) => {
setlocation(e.target.value);
filterLocations(e.target.value);
}}
/>
<ul>
{dropDownLocations.map((i) => (
<li key={i}>{i}</li>
))}
</ul>
</div>
</div>
);
}
export default App;
Ответ №1:
Вам не нужно усложнять это, просто отфильтруйте массив на основе ввода пользователя
const filterLocations = (userInput) => {
setdropDownLocations(
allLocations.filter((location) => location.includes(userInput))
);
};
Я упростил вам задачу в этом рабочем примере:
Комментарии:
1. Спасибо, это нормально работает, но у меня есть еще 1 проблема, проблема в том, что вы все сначала набираете что-то, что работает нормально, но когда я стираю весь введенный текст, он показывает весь отображаемый элемент.
2. Что это такое? Он не фильтруется, когда входные данные пусты?
3. да, он не фильтруется, когда мы очищаем поле ввода
Ответ №2:
Это setState
асинхронная функция, и поэтому ваша текущая реализация работает неправильно, так как вы пытаетесь прочитать state
ее до ее обновления.
Обновите свою filterLocations
функцию следующим образом:
const filterLocations = (e) => {
const location = e.target.value;
const filteredLocation = allLocations.filter(i => i.includes(location));
setlocation(location);
setdropDownLocations(filteredLocation)
};
И обновите свой input
тег следующим образом:
<input value={location} onChange={filterLocations} />
Ответ №3:
Это не работает, потому что для каждого местоположения вы устанавливаете раскрывающееся местоположение, и если оно не содержит местоположения, вы снова устанавливаете его в пустой массив [].
allLocations.map((i) => {
if (i.includes(location)) {
console.log("true at ", i);
setdropDownLocations([...dropDownLocations, i]);
} else {
setdropDownLocations([]);
}
});
Лучшим подходом было бы:
setDropDownLocation([...allLocations].filter((i) => i.includes(userInput))
Ответ №4:
Есть некоторые ошибки в том, что вы сделали, я внес некоторые изменения, попробуйте запустить код, который я написал.
import logo from "./logo.svg";
import "./App.css";
import { useState, useEffect } from "react";
const ALL_LOCATIONS = ['F-1', 'F-2', 'G-1', 'G-2'];
function App() {
// location entered by the user
const [location, setLocation] = useState("");
const [dropDownLocations, setDropDownLocations] = useState([]);
function onLocationInputChange(event){
setLocation(event.target.value);
setDropDownLocations(ALL_LOCATIONS.filter((item)=>item.includes(event.target.value)))
}
return (
<div className="App">
<div>
<input value={location} onChange={onLocationInputChange} />
<ul>
{dropDownLocations.map((loc) => (
<li key={`${location}-${loc}`}>{loc}</li>
))}
</ul>
</div>
</div>
);
}
export default App;
Комментарии:
1. @Сами Малик, я надеюсь, что это вам поможет!!
2. Мы всегда рады Вам @SamiMalik.
3. один вопрос, который я хочу задать, заключается в том, что если функция настройки состояний асинхронна, но она обновляет пользовательский интерфейс на месте, не могли бы вы, пожалуйста, рассказать мне, как она обновляет пользовательский интерфейс, но не обновляет значение состояния в точном отображении
4. Спасибо, что спросили ! когда мы обычно выполняем вызовы Api в этом случае, требуется немного времени, когда на самом деле асинхронные функции играют хорошую роль, но здесь не та сцена, и если мы посмотрим на React, как только состояние обновляется, React отображает компонент, поэтому в соответствии с нашим кодом пользовательский интерфейс обновляется.
5. @SamiMalik вы новичок в React?
Ответ №5:
Это вызвано тем фактом, что ваш onChange
обработчик определен прямо в JSX, в результате чего React создает новую функцию при каждом рендеринге (то же самое относится и к filterLocations
одному).
Вы всегда должны пытаться извлечь каждую часть логики JS за пределами компонента или, по крайней мере, запомнить их, вот как:
import React, { useState, useCallback } from "react";
import logo from "./logo.svg";
import "./App.css";
const ALL_LOCATIONS = ['F-1', 'F-2', 'G-1', 'G-2'];
function App() {
// location entered by the user
const [location, setLocation] = useState("");
// locations shown to the user in dropdown (filterable)
const [dropDownLocations, setDropDownLocations] = useState([]);
const onLocationInputChange = useCallback(
(ev) => {
// In case no target passed to callback, do nothing
if (!ev || !ev.target || !ev.target.value) {
return;
}
const userInput = ev.target.value;
// Filter so that if user input matches part of the location
// it gets not filtered out
setDropDownLocations([
...ALL_LOCATIONS.filter(
(loc) =>
loc.startsWith(userInput) ||
loc.endsWith(userInput) ||
loc.indexOf(userInput) !== -1
),
]);
// Finally update the location var
setLocation(userInput);
},
[setDropDownLocations]
);
return (
<div className="App">
<div>
<input value={location} onChange={onLocationInputChange} />
<ul>
{dropDownLocations.map((loc) => (
<li key={`${location}-${loc}`}>{loc}</li>
))}
</ul>
</div>
</div>
);
}
export default App;