У меня есть собственное приложение для реагирования. И у меня есть функция поиска. Проблема, с которой я столкнулся, заключается в том, что функция поиска работает только тогда, когда в текстовое поле введено все слово.
Так например работает Эдельхерт. Но если пользователь вводит: Эд - то ничего не происходит.
И если пользователь ждет секунду в текстовом поле поиска. Затем выскакивает эта ошибка:
VM270:1 Uncaught SyntaxError: Unexpected identifier 'Promise'
Итак, API поиска выглядит:
import { API_URL } from "@env";
import { retrieveToken } from "../../services/authentication/token";
export const fetchAnimalData = async (text) => {
const token = await retrieveToken();
try {
if (token) {
const response = await fetch(`${API_URL}/api/animals/?name=${text}`, {
method: "GET",
headers: {
Authorization: `Token ${token}`,
Accept: "application/json",
"Content-Type": "application/json",
},
});
return await response.json();
} else {
throw new Error(token);
}
} catch (error) {
console.error("There was a problem with the fetch operation:", error);
throw error;
}
};
и контекст поиска:
/* eslint-disable prettier/prettier */
import React, { createContext, useEffect, useState } from "react";
import { fetchAnimalData } from "./animal/animal.service";
export const SearchAnimalContext = createContext();
export const SearchAnimalContextProvider = ({ children }) => {
const [searchAnimal, setSearchAnimal] = useState([]);
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [input, setInput] = useState("");
useEffect(() => {
fetchAnimalData();
}, [searchAnimal]);
const performSearch = async (text) => {
setLoading(true);
setError(null);
setTimeout(() => {
fetchAnimalData(text)
.then((response2) => {
setResults(response2);
setLoading(false);
})
.catch((err) => {
setLoading(false);
setError(err);
});
});
};
return (
<SearchAnimalContext.Provider
value = {{
results,
setResults,
searchAnimal,
setSearchAnimal,
input,
setInput,
performSearch,
loading,
error,
}}>
{children}
</SearchAnimalContext.Provider>
);
};
И компонент с полем поиска:
import React, { useContext, useState } from "react";
import { AccordionItemsContext } from "../../../services/accordion-items.context";
import { AnimalDetailToggle } from "../../../components/general/animal-detail-toggle-view";
import { CategoryContext } from "../../../services/category/category.context";
import { CategoryInfoCard } from "../components/category-info-card.component";
import { SafeArea } from "../../../components/utility/safe-area.component";
import { SearchAnimalContext } from "../../../services/search-animal.context";
import { Searchbar } from "react-native-paper";
export const CategoryScreen = ({ navigation }) => {
useContext(AccordionItemsContext);
const { loading, categoryList } = useContext(CategoryContext);
const { performSearch, results, setInput, input } = useContext(SearchAnimalContext);
const [searchTimer, setSearchTimer] = useState(null);
return (
<SafeArea>
{loading && (
<LoadingContainer>
<ActivityIndicator animating = {true} color = {MD2Colors.blue500} />
</LoadingContainer>
)}
<Searchbar
placeholder = "search animalll"
onChangeText = {(text) => {
if (searchTimer) {
clearTimeout(searchTimer);
}
if (!text.length) {
setInput("");
return;
}
setInput(text.substring(0));
setSearchTimer(setTimeout(performSearch(text), 1000));
}}
value = {input}
/>
</SafeArea>
);
};
А для бэкэнда я использую Django. Одно из мнений такое:
from django_filters.rest_framework import DjangoFilterBackend
# from WelzijnAdmin.permissions import AdminReadOnly
from rest_framework import permissions, viewsets
from rest_framework.authentication import TokenAuthentication
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from django.contrib.auth.decorators import permission_required
from rest_framework import filters
from .models import Animal, Category
from .serializers import (AnimalSerializer, CategorySerializer,
MainGroupSerializer)
class AnimalViewSet(viewsets.ModelViewSet, permissions.BasePermission):
queryset = Animal.objects.all().order_by('name')
serializer_class = AnimalSerializer
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
filterset_fields = ['name']
search_fields = ['name']
class CategoryViewSet(viewsets.ModelViewSet, permissions.BasePermission):
"""
This API endpoint allows for the viewing of animal categories.
All categories include their direct subcategories and animals.
- To view a specific category, append the url with its [/id](/api/categories/1/).
- To get all top-level categories use [/main_groups](/api/categories/main_groups).
"""
def get_serializer_class(self):
if hasattr(self, 'action') and self.action == 'main_groups':
return MainGroupSerializer
return CategorySerializer
queryset1 = Category.objects.all().order_by('name')
queryset = CategorySerializer.eager_load(queryset1)
serializer_class = get_serializer_class(super)
permission_classes = (IsAuthenticated,)
@action(methods=['get'], detail=False)
# @permission_required("category")
def main_groups(self, request):
"""
Returns a list of top level Categories.
- To view a specific category, append the url with its [/id](/api/categories/1/).
"""
main_groups = Category.objects.filter(category_id__isnull=True)
serializer = self.get_serializer(main_groups, many=True)
return Response(serializer.data)
И если я пойду в
http://127.0.0.1:8000/api/animals/
а затем выберите фильтр и введите в поле поиска el, затем отфильтруются животные, у которых есть буквы el:
[
{
"id": 15,
"name": "Blauwgele Ara",
},
{
"id": 71,
"name": "Edelhert",
{
"id": 19,
"name": "Edelpapegaai",
}]
или я набираю ar:
{
"id": 15,
"name": "Blauwgele Ara",
},
{
"id": 24,
"name": "Bobakmarmot",
}
Что я уже сделал? Конечно, много гуглил. Смотрю ролики на ютубе. Например этот:
https://thewikihow.com/video_i1PN_c5DmaI
Но я не вижу ошибки, мешающей частичному поиску слова.
Вопрос: как реализовать частичный поиск по слову?
@МайклБал. Вы имеете в виду, какое значение возвращается? Или что это значит? Это означает, что не каждый раз будет вызываться база данных
поскольку на основе вашего API вы будете отправлять текст: например, «Эд» вместо «Эдельхерт», убедитесь, что ваш API действительно ищет животных, в которых есть «Эд».
@отображаемое имя. Возможно, я вас не правильно понимаю». Но это, конечно, пример. Я имею в виду в целом - когда набирается слово... ti, то в результатах поиска должны всплывать elvar, eland, слон. Я использую бэкэнд Django. Пользователь может выполнить поиск по части слова, а затем всплывут все слова целиком с первыми введенными символами.
Ах хорошо. Я этого не знал. Я тоже учусь. Но что я сделал. В бэкэнде я изменил это:
class AnimalViewSet(viewsets.ModelViewSet, permissions.BasePermission):
queryset = Animal.objects.all().order_by('name')
serializer_class = AnimalSerializer
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
filterset_fields = ['name']
search_fields = ['name']
def get_queryset(self):
qs = Animal.objects.all()
name = self.request.query_params.get('name')
if name is not None:
qs = qs.filter(name_icontains=name)
return qs
И в интерфейсе я изменил это:
export const fetchAnimalData = async (text) => {
const token = await retrieveToken();
try {
if (token) {
const response = await fetch(`${API_URL}/api/animals/?search=${text}`, {
method: "GET",
headers: {
Authorization: `Token ${token}`,
Accept: "application/json",
"Content-Type": "application/json",
},
});
return await response.json();
} else {
throw new Error(token);
}
} catch (error) {
console.error("There was a problem with the fetch operation:", error);
throw error;
}
};
И теперь это работает.
Что возвращает PerformSearch
setSearchTimer(setTimeout(performSearch(text), 1000));
?