setting Date value on LocalStorage - reactjs

I would like some help to set this date Value into a LocalStorage and then When reloading the app, I would like that the default value of the date component was retrieved from local Storage. Right Now, I'm Using TextField with type date on React js.
const [dateBegin,setDateBegin] = React.useState(new Date())
<TextField
id="date"
label="Início "
type="date"
multiline={false}
onChange={
(e)=>{setDateBegin(new Date( e.target.value));
localStorage.setItem('#legis/datebegin',dateBegin)
}}
InputLabelProps={{
color:'secondary',
className:"DatePicker",
style : {color:"#ffff",},
shrink: true,
}}
inputProps={{
style: { color: "#ffff" },
}}
/>
<div style = {{marginLeft:50}}>
<TextField
However, This is not working right now. Would please help me how to set the date value and then when to retrieve, and if possible how to set the default value of this TextField as the value I retrieved from localStorage?

You trying to save a Date object in local storage where it accepts string only as the key value.
You can parse the string date you saving and then it'll work fine or as an alternative, use a string date format if possible in your use case:
const dateObjFromString = new Date(localStorage.getItem('date'))

In addition to what #Dvir Hazout said, if you read from a state variable right after setting it, the value will always be stale.
const [val, setVal] = useState(1)
return (
<div
onClick={() => {
setVal(2)
console.log(val) // logs 1 on first click, 2 on subsequent clicks
}}
/>
)
Instead, you need to assign it to a normal variable:
const [val, setVal] = useState(1)
return (
<div
onClick={() => {
const newVal = 2
setVal(newVal)
console.log(newVal) // works as expected
}}
/>
)

Related

Passing value to hidden input from dropdown menu in react

I have react-select dropdown menu and hidden input which I pass to form when submiting...
using useState hook I created variable which tracks changes to react-select dropdown menu.
Hidden input has this variable as value also. I thought this would be enough.
But when I submit the form, console. log shows me that value of input is empty despite that variable that was selected from dropdown menu is actually updated.
I mean variable that I have chosen console logs some value, but hidden input thinks that it is still empty.
Does it means I have to rerender manually page each time I change that variable so input gets it's new value using useEffect ? Which is bad solution for me, I don't like it, thought it would be done automatically.
Or instead of useState I must create and use variable via Redux ? Which I also don't like, use redux for such small thing fills overcomplicated.
Isn't there any nice elegant solution ? :)
import { useForm } from 'react-hook-form';
const [someVar,setSomeVar]=useState('');
const {
register,
handleSubmit,
formState: { errors },
} = useForm({ mode: 'onBlur' });
const handleFormSubmit = (data) => {
console.error('success');
};
const handleErrors = (errors) => {
console.error(errors);
console.log(document.getElementsByName('hiddenInput')[0].value);
};
const options = {
hiddenInput: {
required: t('hiddenInput is required'),
},
};
.......
<form onSubmit={handleSubmit(handleFormSubmit, handleErrors)}>
<Select
options='...some options list'
onChange={(value) => setSomeVar(value)}
/>
<input
name='hiddenInput'
value={someVar}
{...register('hiddenInput', options.hiddenInput)}
/>
<button>submit</button>
</form>
UPDATED
Its because getElementsByName returns an array of elements.
You probably want
document.getElementsByName('hiddenInput')[0].value
I should add that really you should use a ref attached to the input and not access it via the base DOM API.
const hiddenRef = useRef(null)
// ...
cosnt handleSubmit =(e)=>{
console.log(hiddenRef.current.value);
}
// ...
<input
name='hiddenInput'
value={someVar}
ref={hiddenRef}
/>
However as you are using react-hook-form you need to be interacting with its state store so the library knows the value.
const {
register,
handleSubmit,
formState: { errors },
setValue
} = useForm({ mode: 'onBlur' });
// ...
<form onSubmit={handleSubmit(handleFormSubmit, handleErrors)}>
<Select
options='...some options list'
onChange={(value) => setValue('hiddenInput', value)}
/>
<input
name='hiddenInput'
{...register('hiddenInput', options.hiddenInput)}
/>
<button>submit</button>
</form>
You can remove const [someVar,setSomeVar]=useState('');
However, this hidden input is not really necessary as you mention in comments. You just need to bind the dropdown to react hook form.
// controller is imported from react hook form
<form onSubmit={handleSubmit(handleFormSubmit, handleErrors)}>
<Controller
control={control} // THIS IS FROM useForm return
name="yourDropdown"
rules={{required: true}}
render={({
field: { onChange, value, name, ref }
}) => (
<Select
options={options}
inputRef={ref}
value={options.find(c => c.value === value)}
onChange={val => onChange(val.value)}
/>
)}
/>
<button>submit</button>
</form>

Why does defaultValue not display anything inside a text field when using an API call (reactjs)

This is the code I have, but it's not displaying properly
<TextField
size="small"
className="typing-container"
defaultValue={thing.thingLastName}
label="Last Name"
onChange={(event) => setFirst(event.target.value)}
required
/>
when I change defaultValue to value, it displays but then you can't edit the field at all. This all displays properly when used earlier inside a h5 tag
You probably want to store the value in local state. Something like:
const MyComp => {
const [value, setValue] = useState(defaultValue)
return (
<TextField
...
onChange={(event) => setValue(event.target.value)}
value={value}
/>
)
}
then whenever your onChange event fires, it updates the value and passes it into the TextField. We don't need to use the defaultValue prop anymore because the useState hook takes a default value and sets that as the initial value for value
Try pass a state to value property, set the state to the default value that you want, later change the value using the onChange property.
function Comp () {
const {value, setValue} = useState('Default Value')
return (
<TextField
value={value}
onChange={(event) => setValue(event.target.value)}
required
/>
)
}

react date picker multi range with react hook form

The reason we use react hook form is that it decreases our state count and increases performance. But I didn't know how to do it when using Date range for one datepicker.
How to keep two data in one controller?
`() => {
const [startDate, setStartDate] = useState(new Date());
const [endDate, setEndDate] = useState(null);
const onChange = (dates) => {
const [start, end] = dates;
setStartDate(start);
setEndDate(end);
};
return (
<DatePicker
selected={startDate}
onChange={onChange}
startDate={startDate}
endDate={endDate}
selectsRange
inline
/>
);
};`
If this piece of code is my code, I can only capture one value with selected, but I need to return 2 values. How can I use this in the best way with the react hook form?
<Controller
name="orderDate"
control={control}
render={({ field }) => (
<DatePicker
selected={field.value}
onChange={(date) => field.onChange(date)}
selectsRange
/>
)}
/>
I've got the exact same issue last week, here is the solution...
You just need to pass (at least) the value to the "Controller function", you achieve that using only the field object.
In any case, When the DatePicker component is used for a date range, it will require a two-position vector data type, where the start and end dates are stored as a string. But if you try to manipulate and control this component via the onChange function that comes from the reack-hook-form it's gonna screw up the entire thing, because is made for a one-to-one data flux. Then the processes are done separately but the vector is still sent to the controller. Here is the code!
const [dateRange, setDateRange] = useState([null, null]);
const [startDate, endDate] = dateRange;
<Controller
//is a prop that we get back from the useForm Hook and pass into the input.
control={control}
//is how React Hook Form tracks the value of an input internally.
name={name}
//render is the most important prop; we pass a render function here.
render={({
//The function has three keys: field , fieldState, and formState.
field, // The field object exports two things (among others): value and onChange
}) => (
<>
<DatePicker
selectsRange={true}
startDate={startDate}
endDate={endDate}
onChange={(e) => {
setDateRange(e);
field.onChange(e);
}}
isClearable={true}
className="form-control"
/>
</>
)}
rules={{
required: `The ${label} field is required`,
}}
/>

Default Values from API in MUI Text field

I have a form that I built using material UI that I would like to have their default values from an API. The main idea is an Edit screen where the user can edit the details and then send them back. However, I cannot seem to get it working at all.
First, I get the data using an axios.get request:
let { id } = useParams();
const [unit, setUnit] = useState("");
useEffect(() => {
axios.get(`http://localhost:3001/units/${id}`).then((response) => {
setUnit(response.data);
});
}, []);
Then I assign the value I want to a state:
const [name, setName] = useState(unit.name);
Finally, I try to set it as the value (since I read that defaultValue cannot be controlled):
<TextField
required
label="Unit Name"
value={name}
onChange={(event) => {setName(event.target.value)}}
fullWidth
variant="outlined"
/>
However, the field does not contain any value. I tried assigning unit.name to a normal const and assign it to the textfield value and it worked but I could not edit it.
In your case, you could change the value to the default value and then you could edit it.
<TextField
required
label="Unit Name"
defaultValue={name}
onChange={(event) => {setName(event.target.value)}}
fullWidth
variant="outlined"
/>
Working solution is setting the name after receiving the Axios request with the data:
setName(response.data.name)
Then set it as the value and using the onChange normally
<TextField
required
label="Unit Name"
value={name}
onChange={(event) => {setName(event.target.value)}}
fullWidth
variant="outlined"
/>
I am running into a similar issue, I am first getting the data on the main component and the passing the entire value to the edit modal, it works fine as long as there is a value, but if any of the value's are null it will essentially crash
for Editing, I just have a new form state in the modal component, and on Change pass that to the form state.

Material-ui autocomplete clear value

I have one problem in my react code.
I use Material-ui and redux-form. I have select input like and after change this select i should reset value in . I use action 'change' from react-form and set value for textfield. But label in still remains. Can i clear or reset value in ?
<Autocomplete
options={list}
getOptionLabel={option => option.name}
onInputChange={onChange}
onChange={onChangeAutoComplete}
noOptionsText='Нет доступных вариантов'
loadingText='Загрузка...'
openText='Открыть'
renderInput={params => (
<Field
{...params}
label={label}
name={fieldName}
variant="outlined"
fullWidth
component={renderTextField}
className={classes.textField}
margin="normal"
/>
)}
/>
Using hooks on the value prop breaks the functionality of the autocomplete component ( at least for me ). Using class, and setting the local state is the same.
Luckily it is a react component, so it have a "key" prop. When the key prop changes, the component is re-rendered with the default values ( which is an empty array since nothing is selected). I used hooks in the parent component and passed the values to the key prop, whenever reset is needed.
<Autocomplete
key={somethingMeaningful} // Bool, or whatever just change it to re-render the component
//...other props
/>
Hope this helps!
Material UI Autocomplete onInputChange callback provides reason argument. If input has been changed by input, reason will be input and if you selected option then reason will be reset.
onInputChange={(event, newInputValue, reason) => {
if (reason === 'reset') {
setValue('')
return
} else {
setValue(newInputValue)
}
}}
setValue is useState and you can pass value state to autocomplete value property.
use value in your <Autocomplete /> like this:
<Autocomplete
value={this.state.value} //insert your state key here
//...other props
/>
Then clear state of that key, to clear the autocomplete field value
I am going to post a very dirty way of clearing the value of Autocomplete. Try it ONLY when nothing else works;
import React, { useRef } from 'react';
...
const autoC = useRef(null);
...
<Autocomplete
...
ref={autoC}
/>
and then when you want to clear the value;
const ele = autoC.current.getElementsByClassName('MuiAutocomplete-clearIndicator')[0];
if (ele) ele.click();
This is what worked for me.
const [name, setName] = useState('');
<Autocomplete
inputValue={name}
onChange={(e,v)=>setName(v?.name||v)}
...
/>
<Button onClick={()=>setName('')}>
Clear
</Button>
You can use something like the following to clear the autocomplete field when an item is selected.
<Autocomplete
value={null}
blurOnSelect={true} />
Note that you may also need to set clearOnBlur={true} if you're using the freeSolo option.
Source https://mui.com/api/autocomplete/#props
I achieved this by updating the inputValue prop where multiple prop is false. If you are using multiple prop, then there is a propblem (bug). Selected values does not get erased.
When I encountered this, it was when options for the autocomplete changed, and wanted to clear the input value. It wouldn't clear with just the options changing. What worked for me is adding a key value onto the autocomplete which depended on the change which necessitated clearing.
To solve this, I created a hook that watches the value state of the autocomplete and set the value of the input if the checkClear returns true;
function useAutocompleteInputClear(watch, checkClear) {
const elmRef = useRef(null);
useMemo(() => {
if (!elmRef || !elmRef.current) return;
if (!checkClear || typeof checkClear !== "function") return;
const button = elmRef.current.querySelector("button")
if (checkClear(watch) && button) {
button.click();
}
}, [watch])
return elmRef;
}
Its first argument is the value that should be watched and its second argument is a function that returns a boolean. if it is true the clearing will happen.
Also, the hook returns a ref that needs to pass as ref prop to Autocomplete.
const elmRef = useAutocompleteInputClear(value, v => !v || !v.id)
<Autocomplete ref={elmRef}
value={value}
...
using onChange property we can clear the value by clicking the clear icon in the following way
<Autocomplete
fullWidth={true}
label={'Source'}
margin={'noraml'}
multiple={false}
name={'Source'}
getOptionSelected={useCallback((option, value) => option.value === value.value)}
ref={SourceRef}
value={formValues.Source === '' ? {label: ''} : {label: formValues.Source}}
options={SourceStatus}
onChange={useCallback((e, v) => {
if (typeof v === 'object' && v !== null) {
handleInputChange(e, v) // help to set the value
} else {
handleInputChange(e, {label: ''}) // help to reset the value
}
})}
/>
In my case for multiselect freeSolo onChange props 3rd argument reason solved my all issues.
AutocompleteChangeReason can be:
blur
clear
createOption
removeOption
selectOption
and 2nd arg of this props gives u already updated list of (multiselect) value/s.
onChange={(_event, newOptions, reason) => {
setOptions(
reason === 'clear' ? [] : [...newOptions.map((o) => Number(o))],
);
}}
If you need only the selected value, set the value to an empty object and render the option to your needs.
<Autocomplete
value={{}}
onChange={handleSelectionChanged}
options={options ?? []}
getOptionLabel={x => (!x ? '' : x?.name ?? '')}
renderInput={params => <TextField {...params} label="" />}
/>
If you are using objects, you can use the following code to clear the field.
Ensure you add isOptionEqualToValue:
<Autocomplete
style={{ width: 250 }}
multiple
id="checkboxes-tags-demo"
options={list}
isOptionEqualToValue={(option, newValue) => {
return option.id === newValue.id;
}}
value={selected}
onChange={(e, val) => handleSelected(e, val)}
getOptionLabel={(option) => option.name}
renderInput={(params) => (
<TextField
{...params}
label="Add to Multiple"
placeholder="Favorites" />
)} />
Just set an empty array in your state through functions, and it'll be cleared.
Try this method:
use onChange method and pass third parameter reason and compare to clear text if reason is clear then executed this function.
<Autocomplete
onChange={(event, newValue, reason) => {
if (reason === 'clear') {
console.log("Put your clear logic here: this condition executed when clear button clicked")
setValue({ title: '', year: '' }) //for reset the value
return
}
}}
/>
One easy way to do this is to pass these props to autocomplete like this:
onChange={handleSkillChange}
inputValue=''
clearOnBlur={true}
onChange is an event handler, which stores the value in the state.
inputValue='' helps to ensure that the text field inside autocomplete will always be empty
clearOnBlur={true} helps to clear the value of the autocomplete component when it loses focus.

Resources