How can I get my <TextField> inside Autocomplete to reset it's default value after form submit?
Currently, the state of formValues during submit remains as the default value?
I've tried to fix the onSubmit function of my form to clear the state of the values, but not able to do so.
How can I clear the value after a user submits?
const { control, handleSubmit } = useForm();
const [formValues, SetFormValues] = useState()
const onSubmit = (data, e) =>
{
console.log(data);
axiosInstance
.patch(URL + slug + '/', {
stock_list: data.stock_list.map(list=>list.symbol),
})
.then((res) =>
{
getFinData(dispatch)(slug);
SetFormValues([''])
console.log(formValues)
});
};
console.log(formValues)
return (
<Container component="main" maxWidth="md">
<div className={classes.container}>
<Grid>
<form noValidate onSubmit = { handleSubmit(onSubmit) }>
<Controller
render={({ onChange ,...props }) => (
<Autocomplete
{...props}
className={classes.inputBar}
id="stock_list"
key={formValues}
name="stock_list"
multiple
options={options}
ListboxComponent={ListboxComponent}
renderGroup={renderGroup}
filterOptions={filterOptions}
filterSelectedOptions
// onChange={(e) => onChange(e.target.value)}
onChange={(e, data) => { onChange(data); SetFormValues(data) }}
getOptionLabel={(option) => option.symbol}
getOptionSelected={(option, value) => option.symbol === value.symbol}
renderOption={(option) =>
{
return (
<>
<span style={{ fontWeight: 500, fontSize: "20px", paddingRight: "1rem" }}>{option.symbol}</span><span style={{ color: "#C6C6C6", fontSize: "24px" }}> | </span><span style={{ paddingLeft: "1rem" }}>{option.company}</span>
</>
)
}}
renderInput={(params) => (
<Zoom in={tabSwitch === 0}>
<TextField
{...params}
style={{ alignItems: 'center' }}
id="stock_list"
name="stock_list"
variant="outlined"
label="Companies"
className={classes.inputBar}
defaultValue={formValues}
/>
</Zoom>
)}
/>
)}
name="stock_list"
control={control}
defaultValue={formValues}
// onChange={([, data]) => data}
/>
{formValues && formValues.length > 0 &&
<Button
variant="contained"
color="primary"
type="submit"
style={{display:"flex",alignItems: 'center',justifyContent:"center"}}
>
Add Stocks
</Button>
}
</form>
</Grid>
</div>
</Container>
);
})
UPDATE:
I have tried implementing your codes but still no success in removing the data from original state?
const [formValues, SetFormValues] = useState([])
const onSubmit = (data, e) =>
{
console.log(data);
axiosInstance
.patch(URL + slug + '/', {
stock_list: data.stock_list.map(list=>list.symbol),
})
.then((res) =>
{
getFinData(dispatch)(slug);
SetFormValues([]);
});
};
return (
<Controller
render={({ onChange ,...props }) => (
<Autocomplete
{...props}
className={classes.inputBar}
id="stock_list"
key={formValues}
name="stock_list"
multiple
options={options}
ListboxComponent={ListboxComponent}
renderGroup={renderGroup}
filterOptions={filterOptions}
filterSelectedOptions
onChange={(e, data) => { onChange(data); SetFormValues(data) }}
getOptionLabel={(option) => option.symbol}
getOptionSelected={(option, value) => option.symbol === value.symbol}
renderOption={(option) =>
{
return (
<>
<span style={{ fontWeight: 500, fontSize: "20px", paddingRight: "1rem" }}>{option.symbol}</span><span style={{ color: "#C6C6C6", fontSize: "24px" }}> | </span><span style={{ paddingLeft: "1rem" }}>{option.company}</span>
</>
)
}}
renderInput={(params) => (
<Zoom in={tabSwitch === 0}>
<TextField
{...params}
style={{ alignItems: 'center' }}
id="stock_list"
name="stock_list"
variant="outlined"
label="Companies"
className={classes.inputBar}
defaultValue={formValues}
value={formValues}
/>
</Zoom>
)}
/>
)}
name="stock_list"
control={control}
defaultValue={[]}
/>
It might be worth noting that my Mui AutoComplete and textfield is wrapped around by React Hook Form controller.
There is error in your code.
When using state, specify the data type to be stored.
E.g
if you are storing array of data, your state should be const [formValues, SetFormValues] = useState([]); not const [formValues, SetFormValues] = useState();
if you are storing string of data, your state should be const [formValues, SetFormValues] = useState(""); not const [formValues, SetFormValues] = useState();
if you are storing integer of data, your state should be const [formValues, SetFormValues] = useState(0); not const [formValues, SetFormValues] = useState();
To clear the state of each of these data
For Array
SetFormValues([]);
For String
SetFormValues("");
For Int
SetFormValues(0);
So correct your code and ty again. It will work for you.
put this code in the then callback of axios SetFormValues([]);
Because defaultValue is default value..
Try looks like this; (add value)
<TextField
style={{ alignItems: 'center' }}
id="stock_list"
name="stock_list"
variant="outlined"
label="Companies"
defaultValue={formValues}
value={formValues}
/>
https://material-ui.com/api/input/#main-content
defaultValue: The default input element value. Use when the component is not controlled.
value: The value of the input element, required for a controlled component.
You can do it this way
const [formValues, SetFormValues] = useState(null)
Put this code in the then callback of axios SetFormValues(null);
OR
const [formValues, SetFormValues] = useState([])
Put this code in the then callback of axios SetFormValues(null);
If any of those two above does not work for you, try storing the values as string in state
E.g const [formValues, SetFormValues] = useState("")
and clear items using SetFormValues(null) or SetFormValues("");
Related
So I have built a movie search app.
On the 4th page we have the ability to search for a specific movie or TV show.
Now I have built a logic that will display "Movies(Tv Shows) not found" when there are no search results.
Here is the code of the entire "Search" Component:
const Search = () => {
const [type, setType] = useState(0);
const [page, setPage] = useState(1);
const [searchText, setSearchText] = useState("");
const [content, setContent] = useState([]);
const [numOfPages, setNumOfPages] = useState();
const [noSearchResults, setNoSearchResults] = useState(false);
const fetchSearch = async () => {
try {
const { data } = await axios.get(`https://api.themoviedb.org/3/search/${type ? "tv" : "movie"}?api_key=${process.env.REACT_APP_API_KEY}&language=en-US&query=${searchText}&page=${page}&include_adult=false`);
setContent(data.results);
setNumOfPages(data.total_pages);
} catch (error) {
console.error(error);
}
};
const buttonClick = () => {
fetchSearch().then(() => {
if (searchText && content.length < 1) {
setNoSearchResults(true);
} else {
setNoSearchResults(false);
}
});
};
useEffect(() => {
window.scroll(0, 0);
fetchSearch();
// eslint-disable-next-line
}, [page, type]);
return (
<div>
<div style={{ display: "flex", margin: "25px 0" }}>
<TextField className="textBox" label="Search" variant="outlined" style={{ flex: 1 }} color="secondary" onChange={e => setSearchText(e.target.value)} />
<Button variant="contained" style={{ marginLeft: "10px" }} size="large" onClick={buttonClick}>
<SearchIcon color="secondary" fontSize="large" />
</Button>
</div>
<Tabs
value={type}
indicatorColor="secondary"
onChange={(event, newValue) => {
setPage(1);
setType(newValue);
}}
style={{
marginBottom: "20px",
}}
>
<Tab style={{ width: "50%" }} label="Search Movies" />
<Tab style={{ width: "50%" }} label="Search TV Shows" />
</Tabs>
<div className="trending">
{content && content.map(c => <SingleContent key={c.id} id={c.id} poster={c.poster_path} title={c.title || c.name} date={c.first_air_date || c.release_date} media_type={type ? "tv" : "movie"} vote_average={c.vote_average} />)}
{noSearchResults && (type ? <h2>Tv Shows not found</h2> : <h2>Movies not found</h2>)}
</div>
{numOfPages > 1 && <CustomPagination setpage={setPage} numOfPages={numOfPages} />}
</div>
);
};
You can see this in action here.
The problem that happens is that even when I have something in my search results, it still shows the Movies(Tv Shows) not found message.
And then if you click the search button again it will disappear.
A similar thing happens when there are no search results.
Then the Movies(Tv Shows) not found message will not appear the first time, only when you press search again.
I don't understand what is going on. I have used .then after my async function and still it does not execute in that order.
Try adding noSearchResults to your useEffect hook. That hook is what tells React when to re-render, and right now it's essentially not listening to noSearchResult whenever it changes because it's not included in the array.
I want to set the value of my custom TextInput to "" when the iconPress is called.
The problem is, that when i call the iconPress, it should clear the text of my TextInputCode field.
But it isnt updated on my screen, isnt clearing the input field.
But it just doesnt change the value/clear it...
This is my code:
const [searchString, setSearchString] = useState("");
const submitHandler = () => {
setSearchString("")}
const changeHandler = (value) => {
setSearchString(value)}
return(...
<TextInputCode
value={searchString}
onChange={(text) => {
changeHandler(text);}}
iconType={
Platform.OS === "android"
? isSearchbarFocused
? "chevron-left"
: "search"
: "search"
}
iconPress={() => {
Platform.OS === "android" && isSearchbarFocused
? (submitHandler(), setSearchbarFocused(false), Keyboard.dismiss())
: "keine suche";
}}
showCancel
placeholderTextColor={colors.text}
onFocus={() => {
setSearchbarFocused(true);
}}
/>
...)
This is the code of my TextInputCode element, but I dont think that this is the problem:
const TextInputCode = ({
iconType,
placeholder,
onChange,
onFocus,
textContentType,
autoCapitalize,
autoCompleteType,
iconPress,
onClear
}) => {
return (
<View style={styles.inputView}>
<Icon name={iconType} onPress={iconPress} size={20}
/>
<TextInput
style={{
flex: 1,
paddingHorizontal: 12,
}}
placeholder={placeholder}
textContentType={textContentType}
autoCapitalize={autoCapitalize}
autoCompleteType={autoCompleteType}
autoCorrect={false}
onChangeText={(e) => onChange(e)}
onFocus={onFocus}
onClear = {onClear}
/>
</View>
);
};
I dont understand why this isnt working. What am I doing wrong?
I am working in react-native and used 'react-hook-forms' for dynamic form creation,
but it's returning empty data object, but it should return values typed in input fields. onSubmit function gives an empty values. Please check my below code. please help me...
//InputBox.js. this my dynamic element where I want access its values in AddDirectries.js
import { useForm, Controller } from 'react-hook-form'
const InputBox = ({ fields, fieldName }) => {
let { control } = useForm();
return (
<>
{ fields.field_unit == null ? <Text style={styles.formsTitle}>{fieldName}</Text> :
<Text style={styles.formsTitle}> {fieldName + "(" + fields.field_unit + ")"}</Text>
}
{[...Array(fields.field_count)].map((item, index) => {
return (
<Controller
control={control}
name={'j' + index}
defaultValue=""
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
onChangeText={value => onChange(value)}
value={value}
></TextInput>
)}
/>
)
})
})
</>)
}
export default InputBox;
//AddDirectries.js here I want access TextInput values.
import { useForm } from 'react-hook-form'
import Element from '../components/Element'
import FormJson from '../../From.json'
export const AddDirectories = (props) => {
let { handleSubmit, control, formState: { errors } } = useForm();
const [elements, setElements] = useState([]);
const [keys, setKeys] = useState([]);
const onSubmit = data => console.log(data);
useEffect(() => {
setKeys(Object.keys(FormJson))
setElements(FormJson)
}, [])
return (
<View style={[styles.mainScreen, { backgroundColor: 'transparent' }]}>
{
keys.map((fieldName, index) => {
return <Element fieldName={fieldName} fields={elements[keys[index]]} key={index}></Element>
})
}
<TouchableOpacity onPress={handleSubmit(onSubmit)} style={[styles1.addButton, { marginBottom: 30 }]}>
<Text>ADD</Text>
</TouchableOpacity>
</View>
)
}
//Element.js
const Element = ({fieldName, fields }) => {
switch (fields.field_type) {
case ("TextField"):
return (<InputLocation fields ={fields} fieldName={fieldName} />)
default: return null;
}
}
export default Element;
I just had the same problem.
instead of :
<Controller
control={control}
name={'j' + index}
defaultValue=""
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
onChangeText={value => onChange(value)}
value={value}
></TextInput>
)}
/>
spread field into textinput:
<Controller
control={control}
name={'j' + index}
defaultValue=""
render={({ field }) => (
<TextInput
{...field}
onChangeText={value => field.onChange(value)}
value={field.value}
></TextInput>
)}
/>
I have a component that gets a detail of a single post via params.id the component works when I remove all the dependencies on the useEffect but doesnt input the value from the redux state to the component states, when I put the dependencies back it gives me an error of title is undefined, but the redux action returns successfully as I have the data, I think the component loads first before receiving the redux action payload?
const UpdatePost = ({ match, history }) => {
const postId = match.params.id;
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [image, setImage] = useState('');
const dispatch = useDispatch();
const postDetails = useSelector(state => state.postDetails);
const { loading, error, post } = postDetails;
const postUpdate = useSelector(state => state.postUpdate);
const {
loading: loadingUpdate,
error: errorUpdate,
success: successUpdate,
} = postUpdate;
useEffect(() => {
if (successUpdate) {
dispatch({ type: POST_UPDATE_RESET });
dispatch({ type: POST_DETAILS_RESET });
history.push('/edit/post');
} else {
console.log(post, postId);
if (!post.title || post._id !== postId) {
dispatch(listPostDetails(postId));
} else {
setTitle(post.title);
setDescription(post.description);
setImage(post.image);
}
}
}, [post, history, dispatch, postId, successUpdate]);
const submitHandler = e => {
e.preventDefault();
dispatch(
updatePost({
_id: postId,
title,
description,
image,
})
);
};
return (
<MotionBox
exit={{ opacity: 0 }}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 1 }}
bgColor={'#eaeaea'}
my="1rem"
border="2px"
borderColor="#eaeaea"
borderRadius="25px"
p={{ base: '2rem 2rem' }}
>
<Heading color={'#435943'} size="lg" pb={'1.5rem'}>
Edit User
</Heading>
{loadingUpdate && <Loader />}
{errorUpdate && <Message status="error">{errorUpdate}</Message>}
{loading && loadingUpdate ? (
<Loader />
) : error ? (
<Message status="error">{error}</Message>
) : (
<form onSubmit={submitHandler}>
<FormControl pb={'1rem'}>
<FormLabel size="md">Edit Post Title</FormLabel>
<Input
borderColor="#d4d6d5"
placeholder="Edit Post Title"
value={title}
onChange={e => setTitle(e.target.value)}
/>
</FormControl>
<FormControl pb={'1rem'}>
<FormLabel size="md">Edit Post Description</FormLabel>
<Textarea
size="md"
value={description}
onChange={e => setDescription(e.target.checked)}
placeholder="Edit Post Descrription"
/>
</FormControl>
<FormControl pb={'1rem'}>
<FormLabel size="md">Edit Post Photo</FormLabel>
<Input
size="md"
placeholder="Edit Post Photo"
value={image}
onChange={e => setImage(e.target.checked)}
/>
</FormControl>
<Button
type="submit"
my={'2rem'}
fontSize={'md'}
fontWeight={600}
color="white"
bg={'green.800'}
_hover={{
background: 'green.600',
}}
_focus={{
outline: 'none',
border: 'none',
}}
>
Update
</Button>
</form>
)}
</MotionBox>
);
};
My textfield/autocomplete field is not rendering on my page. I have wrapped react-hook-form around it to help me control the form.
Here the error I get from my console:
index.js:1 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
at Controller
Here is my autocomplete form, I cant seem to find any help about this on other threads,
<form noValidate onSubmit={handleSubmit(data => setData(data))}>
<Controller
render={({ onChange, ...props }) => (
<Autocomplete
className={classes.container}
id="stock_list"
name="stock_list"
multiple
options={inputOptions.companies}
filterOptions={filterOptions}
filterSelectedOptions
getOptionLabel={(option) => option.symbol}
getOptionSelected={(option, value) => option.symbol === value.symbol}
renderOption={(option) =>
{
return (
<>
<span style={{ fontWeight: 500, fontSize: "20px", paddingRight: "1rem" }}>{option.symbol}</span><span style={{ color: "#C6C6C6", fontSize: "24px" }}> | </span><span style={{ paddingLeft: "1rem" }}>{option.company}</span>
</>
)
}}
renderInput={(params) => (
<TextField
{...params}
style={{ alignItems: 'center' }}
id="stock_list"
name="stock_list"
variant="outlined"
label="Companies"
className={classes.container}
component={TextField}
/>
)}
/>
)}
name="stock_list"
onChange={([event, data]) => {
return data;
}}
control={control}
defaultValue=""
/>
</form>
How did I structure my <Controller> <Autocomplete> and or <TextField> wrong here?
edit: Here is how im getting my inputOptions
const [inputOptions, setInputOptions] = useState({ companies: [] });
useEffect(() =>
{
Axios.get("https://app.stockbuckets.io/tickers/").then((res) =>
{
setInputOptions({ companies: res.data });
});
}, [setInputOptions]);
Change the dependency array in your useEffect to [inputOptions] and not [setInputOptions], that should help at least.