I want to set focus to Autosuggest input element (function components) automatically in React/TypeScript. I tried different solutions but they all failed for me. I added the full code without any modification.
NumberAutoForm.tsx
import React, {useState, useEffect} from 'react';
import {useDispatch, useSelector} from 'react-redux';
import useForm from 'react-hook-form';
import {useId} from 'react-id-generator';
import {getInfoByType} from '../../core/typeAuto';
import {useStepsContext} from '../../utils/StepsProvider';
import {hasCityZone} from '../../redux-data/city/cityReducer';
import {AutoComplete} from '../MainPage/AutoComplete/AutoComplete';
import {getPrivelege} from '../../redux-data/insurance/insuranceSelector';
import SquareLoader from 'react-spinners/SquareLoader';
import {config} from '../../assets/config';
import {getVehicle, getVehicleData, getVehicleError, getVehicleLoading} from '../../redux-data/vehicle/vehicleReducer';
import serviceOsago from '../../service/serviceOsago';
import {setOfferMark, setOfferModel} from '../../redux-data/offer/offerReducer';
import {setDataOrder} from '../../redux-data/insurance/insuranceReducer';
import CustomField from '../MainPage/CustomField';
import Select from "react-select";
import {getOptionsByKind} from "../../core/typeAuto";
const NumberAutoForm = (props) => {
const isCityZone = useSelector(hasCityZone);
const vehicle = useSelector(getVehicleData);
const isLoading = useSelector(getVehicleLoading);
const privilege = useSelector(getPrivelege);
const regError = useSelector(getVehicleError);
const [vehicleEngineOptions, setVehicleEngineOptions] = useState([{}]);
const [engineType, setEngineType] = useState("");
const {register, handleSubmit, errors} = useForm({
reValidateMode: 'onChange',
mode: 'onChange',
defaultValues: {
privilege
}
});
const handleChangeEngineType = (e: any) => {
vehicle.type = e.value;
setEngineType(e);
};
const [checkboxId] = useId(1, 'checkbox');
const [formId] = useId(1, 'form');
const dispatch = useDispatch();
const {goTo} = useStepsContext() as any;
const onSubmit = async (data: any) => {
if (!vehicle || (vehicle && !vehicle.type)) {
await dispatch(getVehicle(data.register_auto));
} else {
if (isCityZone) {
dispatch(setDataOrder(data));
goTo(2);
}
}
};
useEffect(() => {
const handle = async () => {
const {modelName, brandName} = vehicle;
if (brandName) {
const marks = await serviceOsago.getMarkCode(brandName);
const mark = marks && marks.length > 0 ? marks.find((m:any)=>m.id === vehicle.id) : null;
dispatch(setOfferMark(mark));
if (modelName && mark) {
const models = await serviceOsago.mapGetModelCode(mark.id);
const findModel = models.find((item: any) => item.label.toLowerCase() === modelName.toLowerCase());
dispatch(setOfferModel(findModel));
}
}
};
const validateVehicleType = (kind) => {
setVehicleEngineOptions(getOptionsByKind(kind));
};
if (vehicle) {
handle();
if (!vehicle.type) {
validateVehicleType(vehicle.kind);
}
}
}, [vehicle]);
return (
<form onSubmit={handleSubmit(onSubmit)} id={formId} noValidate>
{(!vehicle || (vehicle && !vehicle.id)) && (
<>
<div className="form-group">
<CustomField
className="vehicle-number"
register={register({
required: true,
pattern: {
value: /[A-zА-я-І-і-Ї-ї]{2}\d{4}[A-zА-я-І-і-Ї-ї]{2}/,
message: 'Реєстраційний номер ТЗ не відповідає правилам перевірки'
},
maxLength: {
value: 8,
message: 'Реєстраційний номер ТЗ не відповідає правилам перевірки',
},
minLength: {
value: 8,
message: 'Реєстраційний номер ТЗ не відповідає правилам перевірки',
}
})}
errors={errors}
name={"register_auto"}
label={''}
placeholder={"АА 00 00 АА"}
onChange={props.handleChange}
defaultValue={props.vehicleNumber}
autoFocus
/>
<p>{regError || (vehicle && !vehicle.id && 'Нiчого не знайдено')}</p>
<SquareLoader loading={isLoading} size={20} color={config.color} css={config.css} />
</div>
<button type="submit" className="btn btn-primary" disabled={isLoading}>
Розрахувати вартість
</button>
</>
)}
{vehicle && (
<div>
<div className="vehicle-info">
<p>
Марка
<br />
<strong>{vehicle.brandName || 'Н/Д'}</strong>
</p>
<p>
Модель
<br />
<strong>{vehicle.modelName || 'Н/Д'}</strong>
</p>
<p>
Номер авто
<br />
<strong>{vehicle.regNumber}</strong>
</p>
<p>
{vehicle.type ? getInfoByType(vehicle.type).name : "Обсяг"}
<br />
{
vehicle.type ? <strong>{getInfoByType(vehicle.type).label}</strong> : <Select options={vehicleEngineOptions} isSearchable={false}
styles={{
control: (provide: any) => ({
...provide,
border: "0.2rem solid #FF0000"
}),
valueContainer: (provide: any) => ({
...provide,
flexWrap: "nowrap"
}),
placeholder: () => ({
color: "#000000",
}),
}}
theme={theme => ({
...theme,
borderRadius: 0,
colors: {
...theme.colors,
primary25: '#1BA876',
primary: '#B4C9C1'
}
})}
onChange={handleChangeEngineType}
value={engineType}
placeholder={"Обсяг двигуна"}
/>
}
</p>
</div>
<div className="checkbox-car">
<div className="form-group form-check" style={{marginRight: '2rem'}}>
<input ref={register} name="privilege" id={checkboxId} type="checkbox" hidden />
<label htmlFor={checkboxId}>Є пільга.</label>
</div>
<div className="form-group form-check">
<input ref={register} name="taxi" id="taxi" type="checkbox" hidden />
<label htmlFor="taxi">Таксі</label>
</div>
</div>
<AutoComplete />
<button type="submit" className="btn btn-primary">
Далі
</button>
</div>
)}
</form>
);
};
export default NumberAutoForm;
AutoComplete.tsx
import React, { useState } from 'react';
import Autosuggest from 'react-autosuggest';
import {useDispatch, useSelector} from 'react-redux';
import {
getErrorCity,
getLoadingCity,
getRegisterCity,
setData,
setError
} from '../../../redux-data/city/cityReducer';
import {getInstanceError} from '../../../utils/getInstanceError';
import theme from './AutoComplete.module.css';
import SquareLoader from 'react-spinners/SquareLoader';
import {config} from '../../../assets/config';
import serviceOsago from '../../../service/serviceOsago';
const getSuggestions = (value, cities) => {
if (!value) return [];
const inputValue = value.trim().toLowerCase();
const inputLength = inputValue.length;
const res = inputLength === 0 ? [] : cities
return res;
};
const renderSuggestion = suggestion => (
<div>
{suggestion.nameFull}
</div>
);
const getSuggestionValue = suggestion => suggestion.nameFull;
export const AutoComplete = () => {
const [touch, setTouch] = useState(false);
const dispatch = useDispatch();
const regCity = useSelector(getRegisterCity);
const loading = useSelector(getLoadingCity);
const [suggestions, setSuggestions] = useState([] as any[]);
const [value, setValue] = useState(regCity);
const [cities, setCities] = useState([])
const error = useSelector(getErrorCity);
const errors = {
regCity: error
};
const {
getClassError,
getMessageError
} = getInstanceError(errors);
const mes = getMessageError('regCity');
const onSuggestionsFetchRequested = ({ value }) => {
setSuggestions(getSuggestions(value, cities));
};
const onSuggestionsClearRequested = () => {
setSuggestions([]);
};
const onChange = (event, {newValue}) => {
setValue(newValue);
serviceOsago.getCityCode(value).
then((value:any)=>setCities(value)
)
};
const onBlur = () => {
setTouch(true);
if (value === '') {
dispatch(setError({
message: 'Це поле обов\'язкове'
}));
}
};
const inputProps = {
placeholder: 'Місто реєстрації автомобіля',
value,
onChange,
onBlur,
disabled: loading
};
return (
<div className={getClassError('regCity', touch)}>
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={onSuggestionsFetchRequested}
onSuggestionsClearRequested={onSuggestionsClearRequested}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
inputProps={inputProps}
onSuggestionSelected={(event, data) => {
dispatch(setData(data.suggestion));
}}
theme={theme}
/>
{mes && <p>{mes}</p>}
<SquareLoader loading={loading} size={20} color={config.color} css={config.css}/>
</div>
);
};
This project uses the following dependencies (package.json):
{
"name": "my-web-site",
"version": "0.1.0",
"private": true,
"dependencies": {
"@kunukn/react-collapse": "^2.2.7",
"@rehooks/window-scroll-position": "^1.0.1",
"@types/dotenv": "=6.1.1",
"@types/express": "=4.17.1",
"@types/js-base64": "=2.3.1",
"@types/lodash": "=4.14.149",
"@types/morgan": "=1.7.37",
"@types/node": "10.17.17",
"@types/node-fetch": "=2.5.0",
"@types/node-sass": "=4.11.0",
"@types/react": "^16.9.16",
"@types/react-autosuggest": "^9.3.13",
"@types/react-dom": "16.8.5",
"@types/react-fontawesome": "=1.6.1",
"@types/react-helmet": "=5.0.3",
"@types/react-input-mask": "^2.0.4",
"@types/react-redux": "^7.1.5",
"@types/react-router-config": "=5.0.0",
"@types/react-router-dom": "^5.1.3",
"@types/react-select": "=3.0.2",
"@types/uuid": "^3.4.6",
"@types/whatwg-fetch": "^0.0.33",
"app-root-path": "^2.0.1",
"axios": "^0.21.1",
"babel-loader": "^8.0.6",
"babel-plugin-import": "^1.12.1",
"body-parser": "^1.18.2",
"bootstrap": "^4.3.1",
"cross-env": "^5.1.3",
"crypto": "^1.0.1",
"customize-cra": "^0.6.0",
"dotenv": "^8.1.0",
"dotenv-webpack": "^1.7.0",
"es6-promise": "^4.2.2",
"express": "^4.17.1",
"fetch-everywhere": "^1.0.5",
"file-loader": "^3.0.1",
"ignore-loader": "^0.1.2",
"ignore-styles": "^5.0.1",
"js-base64": "^2.4.3",
"less": "^3.9.0",
"less-loader": "^5.0.0",
"lodash": "^4.17.4",
"lodash.throttle": "^4.1.1",
"morgan": "^1.9.1",
"node-fetch": "^2.6.0",
"node-sass": "^4.12.0",
"nodemon": "^1.19.2",
"odata-query": "6.0.0-1",
"rc-steps": "^3.5.0",
"re-reselect": "^3.4.0",
"react": "^17.0.2",
"react-app-rewire-less": "^2.1.3",
"react-app-rewired": "^2.1.3",
"react-autosuggest": "^9.4.3",
"react-bootstrap": "^1.0.0-beta.15",
"react-countdown": "^2.3.2",
"react-dom": "^17.0.2",
"react-dropdown-date": "^2.2.7",
"react-ga": "^2.6.0",
"react-helmet": "^5.2.0",
"react-hook-form": "^3.28.2",
"react-hotjar": "^2.0.2",
"react-id-generator": "^3.0.0",
"react-input-mask": "^2.0.4",
"react-lines-ellipsis": "^0.14.1",
"react-modal": "^3.11.1",
"react-modern-calendar-datepicker": "^3.1.6",
"react-owl-carousel2": "^0.3.0",
"react-redux": "7.1.3",
"react-router-config": "4.4.0-beta.8",
"react-router-dom": "^5.1.2",
"react-scripts": "3.0.1",
"react-scripts-ts": "2.13.0",
"react-select": "=3.0.8",
"react-spinners": "=0.7.1",
"redux": "=4.0.4",
"redux-actions": "=2.6.5",
"redux-thunk": "=2.3.0",
"reselect": "=4.0.0",
"serve-favicon": "=2.4.5",
"ts-loader": "=6.0.4",
"ts-node": "=8.3.0",
"use-media": "=1.4.0",
"use-react-router": "=1.0.7",
"uuid": "=3.3.3",
"webpack-cli": "=3.3.8",
"webpack-node-externals": "=1.7.2",
"whatwg-fetch": "=3.0.0"
},
"scripts": {
"prestart": "yarn run build",
"start": "yarn start:server",
"start:dev": "yarn run build && yarn start:server:dev",
"start:server": "cross-env NODE_ENV=production ts-node build_server/server.js",
"start:server:dev": "cross-env NODE_ENV=development ts-node build_server/server.js",
"start:client": "react-app-rewired start",
"build:server": "ts-node node_modules/webpack/bin/webpack.js --config webpack.server.config.js",
"build:client": "react-app-rewired build",
"build": "yarn run build:client && yarn run build:server",
"test": "react-app-rewired test --env=jsdom",
"eject": "react-app-rewired eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"concurrently": "=3.5.1",
"style-loader": "=1.0.0",
"typescript": "3.5.3"
}
}
Any ideas how to set focus on such component? Thank you.


You can use the
inputPropsprop of thereact-autosuggestcomponent to pass arefobject to theinputelement, and then use theuseEffecthook to call thefocusmethod on therefwhen the component mounts.For example:
You can see the whole example here: codesandbox.io