#reactjs #material-ui #autosuggest
Вопрос:
У меня есть этот экран [![Экран][1]][1], на котором я могу искать бизнес с помощью автозаполнения (поддерживается автозаполнением Google maps). Если пользователь вводит Ввод текста, который не был предложен placeAutoComplete, сервер выбирает опцию поиска текста на картах и отображает результаты на карте.
Теперь моя проблема в том, что, когда пользователь нажимает на место на карте, я хочу, чтобы название этого места отображалось в режиме самовнушения.
Я изо всех сил пытаюсь понять, как привязать значение только тогда, когда оно выбрано (из внешнего события)
Естественно, я попытался установить значение (если оно равно нулю, пока нет выбора): я получаю эту ошибку
VM11047 react_devtools_backend.js:2560 Material-UI: A component is changing the uncontrolled value state of Autocomplete to be controlled.
Elements should not switch from uncontrolled to controlled (or vice versa).
Decide between using a controlled or uncontrolled Autocomplete element for the lifetime of the component.
The nature of the state is determined during the first render, it's considered controlled if the value is not `undefined`.
Мой код очень прост, я не знаю, стоит ли им делиться:
EntityAutocomplete.js
import React, {useState} from 'react';
import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete';
import {useTranslation} from "next-i18next";
import {useRouter} from "next/router";
import {REGION_LIST, PLACE_CANDIDATE_LIST} from "../../../constants/graphQueries";
import {useQuery} from "@apollo/client";
import logger from "../../../lib/logger";
import {defaultIfNull} from "../../../constants/util";
export default function EntityAutocomplete(props) {
const [value, setValue] = useState();
const [searchText, setSearchText] = useState([]);
const [options, setOptions] = useState([]);
const [loadingTextSearch, setLoadingTextSearch] = useState(true);
const {t} = useTranslation()
const router = useRouter()
const isSearchEmpty = searchText.length == 0 || searchText.trim().length == 0;
const {loading, data, error} = useQuery(REGION_LIST, {
variables: {name: searchText}, onCompleted: onServerResponse, skip: isSearchEmpty
})
// triggered if a text was entered manually (not from list)
const {loadingMarkers, markersData, markerSearchError} = useQuery(PLACE_CANDIDATE_LIST, {
variables: {name: searchText},
onCompleted: onTextSearchResponse,
skip: !loadingTextSearch,
fetchPolicy: "no-cache",
notifyOnNetworkStatusChange: true
})
// disable trigger just after executing the request
if (loading) {
// logger.debug("loading")
}
if (error) {
logger.info("error: ", error)
}
function onServerResponse(data) {
if (data) {
setOptions(data.locationMany);
}
}
function onTextSearchResponse(data) {
const {onMarkersChanged} = props
if (data) {
const locationCandidateMany = data.locationCandidateMany;
if (onMarkersChanged)
onMarkersChanged(locationCandidateMany)
//must be placed here otherwise this callback is not called if disabled before response
if (loadingTextSearch)
setLoadingTextSearch(false)
}
}
function valueChanged(event, newValue) {
setValue(newValue);
const onEntitySelected = props.onEntitySelected;
if (isAutoSuggestion(newValue)) {
if (onEntitySelected != null)
onEntitySelected(value)
return
}
//text was typed with enter: find matching results
setLoadingTextSearch(true)
}
function isAutoSuggestion(option) {
return option?.source != null;
}
function getOptionLabel(option) {
return isAutoSuggestion(option) ? option.name : option;
}
return (
<Autocomplete
value={props.selected}
freeSolo
onChange={valueChanged}
onInputChange={(e, value) => {
setSearchText(value)
}}
options={options}
getOptionLabel={getOptionLabel}
disableClearable
renderInput={(params) => (
<TextField
{...params}
label={t(`service.search.placeholder`)}
margin="normal"
variant="outlined"
InputProps={{...params.InputProps, type: 'search'}}
/>
)}
/>
);
}
И родительский компонент называет это так:
<Grid item className={classes.entitySelector}>
<EntityAutocomplete label={t(`common.entityHome.selectEntity.entityLabel`)}
entityName={issue.entity?.name} onEntitySelected={onPlaceSelected}
onSelectedEntityInfoLoaded={onSelectedEntityInfoLoaded}
onMarkersChanged={setMarkers} selected={selectedPlace}/>
</Grid>
Я также попытался добавить эффект, чтобы оставить доступным только один параметр, если select
он не равен нулю:
const {selected} = props
useEffect(() => {
if (selected != null) {
setOptions([selected])
}
}, [selected])
but it doesn’t work
[1]: https://i.stack.imgur.com/t3dhG.png