Reputation: 313
apologies as I'm still fairly new to React Native. I encountered this issue upon replacing some poorly styled dropdown picker with a 3rd party library (react-native-dropdown-picker). I was able to create a pretty workable solution, but the form uses react-hook-forms for submission and validation purposes. It's currently indicating that my searchable dropdown components are still empty, even when they are clearly displaying values
export const ControlledSearchableInput = (
props: ControlledSearchableInputProps
) => {
return (
<Controller
control={props.control}
name={props.name}
defaultValue={props.defaultValue}
render={({ onChange, value }) => (
<SearchableInput
onChange={onChange}
value={value ?? value.name}
dataType={props.dataType}
hideLabel={props.accountType ?? false}
accountType={props.accountType ?? false}
placeholder={props.placeholder ?? ""}
error={props.error}
/>
)}
/>
);
};
export function SearchableInput<T>({
onChange,
value,
dataType,
error,
label,
hideLabel,
groupPosition,
placeholder,
disabled = false,
accountType,
}: SearchableInputProps<T>) {
const [open, setOpen] = useState(false);
const [val, setVal] = useState<string>(value);
const [loading, setLoading] = useState(false);
const getDataAsync = async (search: string) => {
if (search) {
setLoading(true);
switch (dataType) {
case "country":
return (await mobileApiManager.Countries.getCountries({ search }))
.results;
case "state":
return (
(await mobileApiManager.States.getStates({ search })).results ?? []
);
}
} else {
setLoading(false);
return [];
}
};
const currentList = useAsync<SearchableInputType[]>((searchText) =>
getDataAsync(searchText)
);
const listItems = currentList.value
? currentList.value.map((item) => {
return { label: item.name, value: item.id };
})
: [];
const [items, setItems] = useState(listItems);
useEffect(() => {
setItems(listItems);
if (listItems.length >= 0) {
setLoading(false);
}
}, [currentList.value]);
return (
<View style={{ marginBottom: error ? 16 : 8 }}>
<DropDownPicker
open={open}
value={val}
loading={loading}
items={items ?? []}
setOpen={setOpen}
setValue={setVal}
setItems={setItems}
searchable
disabled={disabled}
placeholder={placeholder ?? ""}
searchPlaceholder="Search..."
labelProps={{ numberOfLines: 1 }}
onChangeSearchText={currentList.execute}
listMode="MODAL"
onChangeValue={onChange}
/>
{!!error && <ErrorMessage text={error} />}
</View>
);
}
export default function EditAddresses(props: EditAddressesProps) {
const { fields, append, remove } = useFieldArray({
control: props.control,
name: "addresses",
keyName: "customIDAddr",
});
return (
<View>
<ProfileRowView marginBottom={`${scale(5)}`} marginTop={`${scale(25)}`}>
<NameText margin={"0"}>{getLocalString(Strings.address)}</NameText>
<AddButtonWithLabel
onPress={() => {
append(defaultAddress);
}}
/>
</ProfileRowView>
{fields.map((item: any, index: number) => (
<View
key={`${item.id}${item.uuid}`}
style={{ marginBottom: scale(13) }}
>
//...Other components
<ControlledSearchableInput
accountType
placeholder={getLocalString(Strings.state)}
control={props.control}
name={`addresses[${index}].state`}
dataType={"state"}
// stateId={`addresses[${index}].stateId`}
defaultValue={item.state ?? ""}
error={props.errors?.addresses?.[index]?.state?.message}
/>
//...Other components
<ControlledSearchableInput
control={props.control}
name={`addresses[${index}].country`}
placeholder={"Country"}
dataType={"country"}
// countryId={`addresses[${index}].countryId`}
accountType
defaultValue={item.country ?? ""}
error={props.errors?.addresses?.[index]?.country?.message}
/>
</View>
))}
</View>
);
}
Any help would be greatly appreciated
Upvotes: 1
Views: 1270
Reputation: 5439
I was able to get this working with the Controller with this configuration.
...
<Controller
...
render={({ field }) => (
<DropDownPicker
value={field.value}
setValue={(callback: any) => field.onChange(callback())}
items={items}
...
Upvotes: 5