Child components not updating global state - reactjs

I am developing a form with controlled components, Material-UI and, react hooks. All of the form data is saved in a global state via a useState setter function.
Additionally, some fields need to be toggled on and off depending on the user's response which implies that its local and global state has to be reset when toggled off.
That said when two or more components are toggled off at the same time one of them fails to update the global form state.
Here is my code:
App.js
imports...
function App () {
const [formState, setFormState] = useState({
fullName: '',
email: '',
ageLevel: '',
numTitle: '',
titleTypes: '',
materialType: '',
subjInterest: ''
})
const handleTxtFldChange = (e, name) => {
setFormState({ ...formState, [name]: e.target.value })
}
return (
<>
<div className='App'>
<form noValidate autoComplete='off'>
<TextField
required
value={formState.fullName}
onChange={e => handleTxtFldChange(e, 'fullName')}
label='fullName:'
/>
<AgeLevelSelect
formState={formState}
setFormState={setFormState}
/>
<NumOfTitles
formState={formState}
setFormState={setFormState}
ageLevel={formState.ageLevel}
/>
<MaterialType
formState={formState}
setFormState={setFormState}
ageLevel={formState.ageLevel}
/>
<SubjOfInterest
formState={formState}
setFormState={setFormState}
ageLevel={formState.ageLevel}
materialType={formState.materialType}
/>
<Button
onClick={() => { submitForm() }}
>
Submit
</Button>
</form>
</div>
</>
)
}
export default App
When Adult is selected from AgeLevelSelect, numTitle and materialType will be toggled on.
The data is saved in its local and global sate.
Component: AgeLevelSelect.js
imports...
const AgeLevelSelect = ({ formState, setFormState }) => {
const [age, setAge] = useState('')
const handleChange = (event) => {
setAge(event.target.value)
setFormState({ ...formState, ageLevel: event.target.value })
}
return (
<FormControl>
<InputLabel>Age level?</InputLabel>
<Select
value={age}
onChange={handleChange}
>
<MenuItem value='School-Age'>School-Age</MenuItem>
<MenuItem value='Teens'>Teens</MenuItem>
<MenuItem value='Adults'>Adults</MenuItem>
</Select>
</FormControl>
)
}
export default AgeLevelSelect
Here we select two from the select options. The data is saved in its local and global sate.
Component: NumOfTitles.js
imports...
const NumTitles = ({ formState, setFormState, ageLevel }) => {
const [titles, setTitles] = useState('')
const [isVisible, setIsVisible] = useState('')
const handleChange = (event) => {
setTitles(event.target.value)
setFormState({ ...formState, numTitle: event.target.value })
}
useEffect(() => {
if (ageLevel === 'Adults') {
setIsVisible(true)
} else {
setValue('')
setIsVisible(false)
setFormState(prevState => {
return { ...formState, materialType: '' }
})
}
}, [ageLevel])
useEffect(() => {
if (ageLevel !== 'Adults') {
setFormState(prevState => {
return { ...formState, materialType: '' }
})
setValue('')
setIsVisible(false)
}
}, [value])
return (
isVisible &&
<FormControl>
<InputLabel id='demo-simple-select-label'>Number of titles:</InputLabel>
<Select
value={titles}
onChange={handleChange}
>
<MenuItem value='One'>One</MenuItem>
<MenuItem value='Two'>Two</MenuItem>
</Select>
</FormControl>
)
}
export default NumTitles
If you made it this far THANK YOU. We are almost done.
Here we select Non-fiction. Data gets save in local and global state.
Additionally, the subject of interest question is toggled on.
Component: MaterialType.js
imports...
const TypeOfMaterial = ({ formState, setFormState, ageLevel }) => {
const [value, setValue] = useState('')
const [isVisible, setIsVisible] = useState('')
const handleChange = (event) => {
setValue(event.target.value)
setFormState({ ...formState, materialType: event.target.value })
}
useEffect(() => {
if (ageLevel === 'Adults') {
setIsVisible(true)
} else {
setValue('')
setIsVisible(false)
setFormState(prevState => {
return { ...formState, materialType: '' }
})
}
}, [ageLevel])
useEffect(() => {
if (!isVisible) {
setFormState(prevState => {
return { ...formState, materialType: '' }
})
setValue('')
setIsVisible(false)
}
}, [isVisible])
return (
isVisible &&
<FormControl component='fieldset'>
<FormLabel component='legend'>Select type of material:</FormLabel>
<RadioGroup name='MaterialTypes' value={value} onChange={handleChange}>
<FormControlLabel
value='Mystery'
control={<Radio />}
label='Mystery'
/>
<FormControlLabel
value='NonFiction'
control={<Radio />}
label='Non-fiction'
/>
</RadioGroup>
</FormControl>
)
}
export default TypeOfMaterial
Finally, we write World War II, in the text field. The data is saved in its local and global sate.
Component: SubjOfInterest.js
imports...
import React, { useState, useEffect } from 'react'
import TextField from '#material-ui/core/TextField'
const SubjOfInterest = ({ formState, setFormState, ageLevel, materialType }) => {
const [textField, setTextField] = useState('')
const [isVisible, setIsVisible] = useState('')
const handleTxtFldChange = (e) => {
setTextField(e.target.value)
setFormState({ ...formState, subjInterest: e.target.value })
}
useEffect(() => {
if (formState.materialType === 'NonFiction') {
setIsVisible(true)
} else {
setIsVisible(false)
}
}, [materialType])
useEffect(() => {
if (formState.materialType !== 'NonFiction') {
setTextField('')
}
}, [ageLevel])
return (
isVisible &&
<TextField
value={textField}
onChange={e => handleTxtFldChange(e)}
label='Indicate subjects of interest:'
/>
)
}
export default SubjOfInterest
At this point the global state looks as follow:
{
fullName:"Jhon Doe",
ageLevel:"Adults",
numTitle:"Two",
materialType:"NonFiction",
subjInterest:"World War"
}
Then if a user changes the selected option (Adults) from the AgeLeveleSelect to a different option (teens for example) the a part of global state (numTitle, materialType, subjInterest) is expected to be cleared, instead I get this:
{
fullName:"Jhon Doe",
ageLevel:"Teens",
numTitle:"Two",
materialType:"",
subjInterest:"World War"
}
Any ideas?
I have tried many things without results.
If anyone can help will be greatly appreciated!!!

You are only clearing the materialType field:
On the NumOfTitles.js file you are setting the field "materialType" instead of the "numOfTitles" field.
On the SubjOfInterest.js you are not clearing any fields.
My suggestion is that you check the "Adults" condition on the parent component. This way you will not update the same state three times (if this occurs at the same time, this can cause some problems).
You can try doing this way:
App.js
function App () {
const [formState, setFormState] = useState({
fullName: '',
email: '',
ageLevel: '',
numTitle: '',
titleTypes: '',
materialType: '',
subjInterest: ''
})
useEffect(() => {
if(formState.ageLevel !== 'Adults') {
setFormState({
...formState,
numTitle: '',
materialType: '',
subjInterest: '',
})
}
}, [formState.ageLevel]);
// ...

Related

How to get date from IonDateTime with Ionic React

I have recently started using react due to the performance it provides, so I'm not used to this new framework. I have searched on this exact topic but cannot find an answer.
Although the problem is very simple, (Just want to return the selected date).
Here's what I currently am trying to do:
let dateValue = format(new Date(), 'yyyy-MM-dd')+ 'T09:00:00.000Z';
const dateChanged = (value: any) => {
console.log("value: ", value);
dateValue = value;
};
const DateModal: React.FunctionComponent<any> = ({ isOpen, onClose }) => {
return (
<IonModal className="datemodal" isOpen={isOpen}>
<IonContent className="dateModalOpen">
<IonDatetime
locale="en-GB"
value={dateValue}
id="datetime"
onChange={() => dateChanged(datetime)}
showDefaultButtons={true}
min="1920"
max="2022"
className="calendar"
presentation="date"
>
<span slot="title">Date of Birth</span>
</IonDatetime>
</IonContent>
</IonModal>
);
};
I recieve an error on the "onChange" (Cannot find name 'datetime'.), this is what I used to do in Angular. I tried to use a template reference by doing "id=datetime", which in Angular was "#datetime". And in so doing would work inside the onChange event.
How do I make this work?
Thank you in advance!
Solved. On react you can use "Controller" to get the data from IonDateTime as follows:
const {
handleSubmit,
control,
setValue,
register,
getValues,
formState: { errors },
} = useForm({
defaultValues: {
fullname: "",
date: "",
gender: "MALE",
email: "",
},
});
console.log(getValues());
/**
*
* #param data
*/
const onSubmit = (data: any) => {
alert(JSON.stringify(data, null, 2));
};
const [ionDate, setIonDate] = useState("");
const dateChanged = (value: any) => {
let formattedDate = format(parseISO(value), "dd-MM-yyyy").replace(
/-/g,
"/"
);
setIonDate(formattedDate);
setshowDate({ isOpen: false });
};
const DateModal: React.FunctionComponent<any> = ({ isOpen }) => {
console.log(isOpen);
return (
<IonModal className="datemodal" isOpen={isOpen}>
<IonContent className="dateModalOpen">
<Controller
render={({ field }) => (
<IonDatetime
value={field.value}
onIonChange={(e) => dateChanged(e.detail.value)}
locale="en-GB"
onChange={dateChanged}
showDefaultButtons={true}
onIonCancel={() => setshowDate({ isOpen: false })}
min="1920"
max="2022"
className="calendar"
presentation="date"
>
<span slot="title">Date of Birth</span>
</IonDatetime>
)}
control={control}
name="date"
rules={{ required: "This is a required field" }}
/>
<IonButton type="submit">submit</IonButton>
</IonContent>
</IonModal>
);
};
};
You just need to use the ionOnChange handler:
<IonDatetime presentation="date"
id="datetime"
onIonChange={(e) => console.log(e)}>
</IonDatetime>

React Country Region Select

I have some code about react-country-region-selector, which is suppose to allow me to select the countries and regions, but countries do not get selected and regions remains a dash. Can someone tell me what went wrong with my code?
P.s I am using this site for my code, https://github.com/country-regions/react-country-region-selector
import { CountryDropdown, RegionDropdown } from 'react-country-region-selector';
import React, { useState } from "react";
const Locations = () => {
const [state, setState] = useState({
country: "",
region: ""
})
const selectCountry = (val) => {
setState({ state: val });
}
const selectRegion = (val) =>{
setState({ state: val });
}
const { country, region } = setState;
return(
<div>
<CountryDropdown
value={country}
onChange={(val) => selectCountry(val)} />
<RegionDropdown
country={country}
value={region}
onChange={(val) => selectRegion(val)} />
</div>
</div>
);
}
return default Locations;
What I currently have:
What I Need:
You just need to do some minor changes.
const selectCountry = (val) => {
setState({ country: val });
}
const selectRegion = (val) =>{
setState({ region: val });
}
const { country, region } = state;
return(
<div>
<CountryDropdown
value={country}
onChange={(val) => selectCountry(val)} />
<RegionDropdown
country={country}
value={region}
onChange={(val) => selectRegion(val)} />
</div>
</div>

How can I load my initialvalue in my form input?

I need to create a modify feature on a value. I have the input setup inside a modal but for some reason I can't seem to pass on the value to the initialValues.
My code starts with ActivityAreas
<Datatable
ref={this.datatable}
rows={this.props.activityAreas}
update={this.props.updateTable}
headers={[
{
key: "name",
title: () => t("entities.activityAreas.name"),
},
{
key: "action",
title: () => t("entities.activityAreas.action"),
render: (_, row) => (
<Flex>
<ClickableLink onClick={() => this.openModalDestroy(row)}>
{t("entities.activityAreas.destroy")}
</ClickableLink>
<ClickableLink onClick={() => this.openModalRename(row)}>
{t("entities.activityAreas.rename")}
</ClickableLink>
</Flex>
),
props: { align: "right" },
},
]}
type={ACTIVITY_AREAS}
/>
The line that says
this.openModalRename(row)
contains the actual line object with name and id. openModalRename looks like this right now
openModalRename = (row) => {
let modalProps = this.modalProps;
modalProps.row=row;
this.props.setModal(RenameActivityArea, modalProps, { width: '500px' })
}
It sends the data to the RenameActivityArea page
That page looks like this:
const RenameActivityArea = ({
values,
handleSubmit,
handleChange,
isValid,
hideModal,
isSubmitting,
setFieldValue,
...props
}) => {
const input = (name, inputProps) => (
<Input
{...getFormInputProps(
{
handleSubmit,
handleChange,
values,
isValid,
...props,
},
name,
inputProps
)}
/>
);
return (
<Form onSubmit={handleSubmit}>
<Header.H2>{t("settings.activityAreas.modActivityAreas")}</Header.H2>
{input("name", { label: "activityAreas.ActivityAreaName" })}
<ButtonRow
flex="0 0 auto"
flow="row"
justify="flex-end"
padding="10px 0px"
>
<Button type="button" outline onClick={hideModal}>
Fermer
</Button>
<Button
loading={isSubmitting}
disabled={!isValid}
onClick={handleSubmit}
>
{t("entities.activityAreas.save")}
</Button>
</ButtonRow>
</Form>
);
};
const initialValues = {
name: "",
};
const mapState = ({ entities }) => ({
activity_area: entities.activity_area,
});
const mapDispatch = (dispatch) => ({
onSubmit: (activity_area) => dispatch(updateActivityAreas(activity_area)),
});
RenameActivityArea.propTypes = {
modalProps: PropTypes.shape(),
handleSubmit: PropTypes.func,
handleChange: PropTypes.func,
hideModal: PropTypes.func,
isSubmitting: PropTypes.bool,
handleBlur: PropTypes.func,
errors: PropTypes.shape(),
touched: PropTypes.shape(),
isValid: PropTypes.bool,
};
const FormWrapped = withForm({
mapPropsToValues: () => initialValues,
validateOnChange: false,
validateOnBlur: true,
validationSchema: schema,
afterSubmit: (values, formik) =>
formik.props.afterModalSubmit(values, formik),
})(RenameActivityArea);
const Connected = connect(mapState, mapDispatch)(FormWrapped);
export default Connected;
I can get the value inside the box if I do this:
<Input {...getFormInputProps({
handleSubmit,
handleChange,
values: props.row, // <- This gives the value
isValid,
...props,
}, name, inputProps)}
/>
But then for some reason, I can't seem to be allowed to modify the value inside the input. It's like if it was read only or something. I am not sure thats the right way of approaching this anyway.
EDIT
getFormInputProps
export const getFormInputProps = (formProps, name, { label = name.replace('Attributes', ''), ...props } = {}) => {
const error = browseObject(formProps.errors, name)
const isTouched = browseObject(formProps.touched, name)
return {
onChange: formProps.handleChange,
label: label && t(`entities.${label}`),
error,
name,
value: browseObject(formProps.values, name) || '',
onBlur: formProps.handleBlur,
touched: isTouched,
...props,
}
}
withForm
export default withForm({
mapPropsToValues,
validateOnChange: false,
validateOnBlur: true,
validationSchema: schema,
afterSubmit: (_, { props: { history } }, { payload: { user } }) => {
history.push(getRedirect(user))
},
})
By adding the value inside the input field i can see it inside the modal but I can't type or change it. The Input does not have any read-only restrictions but still does not allow typing. So I might not be doing this the right way.
It looks like it uses Formik
https://formik.org/docs/overview
EDIT:
The utils/form is the following. As you can see it uses Formik
import { withFormik } from 'formik'
import { debounce } from 'lodash'
import objectToFormData from 'object-to-formdata'
import * as yup from 'yup'
import API from '../config/api'
import t from './translate'
import { DEFAULT_TEXT_WRAP, DEFAULT_TEXT_WRAP_THRESHOLD } from '../config/constants'
yup.setLocale({
mixed: {
required: () => t('errors.fieldIsRequired'),
},
})
const DEFAULT = (afterSubmit = () => { }) => ({
handleSubmit: (values, formik) => {
formik.props.onSubmit(values).then((action) => {
formik.setSubmitting(false)
afterSubmit(values, formik, action)
})
},
})
export default ({
afterSubmit = (values, { props: { afterSubmit: after } }) => after && after(values),
...attrs
}) => withFormik(Object.assign({}, DEFAULT(afterSubmit), attrs))
export async function checkExists(url, params) {
const response = await fetch(API.getUrl(url, params), {
method: 'GET',
headers: API.headers(),
})
return response
}
export const asyncSelectProps = formProps => key => ({
onChange: (items) => {
formProps.setFieldValue(key, items.map(item => item.id), false)
if (!formProps.touched[key]) {
formProps.setFieldTouched(key, true, false)
}
formProps.setFieldError(key, (!items.length) ? t('errors.mustContainAtLeastOneItem') : undefined, false)
},
touched: formProps.touched[key],
error: formProps.errors[key],
})
/* eslint prefer-arrow-callback: 0 */
/* eslint func-names: 0 */
yup.addMethod(yup.string, 'asyncUnique', function (url, body, message) {
return this.test({
name: 'asyncUnique',
message,
test: debounce(async (value) => {
if (value && value.length > 0) {
const response = await checkExists(`/exists/${url}`, body(value))
const { exists } = await response.json()
return !exists
}
return true
}, 500),
})
})
export const browseObject = (object, path) => {
const parsePath = (path.constructor === String) ? path.split('.') : path
const [key, ...rest] = parsePath
if (object && object[key] !== undefined) {
const next = object[key]
return (rest.length > 0) ? browseObject(next, rest) : next
}
return null
}
export const getFormInputProps = (formProps, name, { label = name.replace('Attributes', ''), ...props } = {}) => {
const error = browseObject(formProps.errors, name)
const isTouched = browseObject(formProps.touched, name)
return {
onChange: formProps.handleChange,
label: label && t(`entities.${label}`),
error,
name,
value: browseObject(formProps.values, name) || '',
onBlur: formProps.handleBlur,
touched: isTouched,
...props,
}
}
export const preventPropagate = callback => (event) => {
event.stopPropagation()
callback(event)
}
export const extractFiles = (files, multiple = false) => (multiple ? files : files[0])
export const fileInputHandler = (formProps, name, multiple = false) => (event) => {
const file = extractFiles(event.target.files, multiple)
formProps.setFieldValue(name, file)
}
export const wrapText = (
text,
maximum = DEFAULT_TEXT_WRAP,
threshold = DEFAULT_TEXT_WRAP_THRESHOLD,
) => {
if ((text.length + threshold) > maximum) {
return `${text.slice(0, maximum)}...`
}
return text
}
export const toFormData = body => objectToFormData(body)
export const PHONE_NUMBER_REGEX = /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/
export const ZIP_CODE_REGEX = /^[A-Za-z]\d[A-Za-z][ -]?\d[A-Za-z]\d$/
EDIT:
So instead of using the const to render my input, I used directly an input field and no I can edit. But why did the const cause the problem?
const RenameActivityArea = ({
values,
touched,
handleSubmit,
handleChange,
handleBlur,
isValid,
hideModal,
isSubmitting,
setFieldValue,
...props
}) => {
return (
<Form onSubmit={handleSubmit}>
<Header.H2>{t('settings.activityAreas.modActivityAreas')}</Header.H2>
<input
type="text"
onChange={handleChange}
onBlur={handleBlur}
value={values.name}
name="name"
/>
<ButtonRow flex="0 0 auto" flow="row" justify="flex-end" padding="10px 0px">
<Button type="button" outline onClick={hideModal}>Fermer</Button>
<Button loading={isSubmitting} disabled={!isValid} onClick={handleSubmit}>{t('entities.activityAreas.save')}</Button>
</ButtonRow>
</Form>
)
}

React-Admin: How to send input values that have been auto filled from an API call?

I have an input 'A' that fetches address data from an API and auto fills inputs 'B' 'C' and 'D' based on that data, but after the inputs have been filled and I try to send that form to my backend, none of those auto filled inputs are sent, just the input 'A' is sent. Furthermore, if i manually edit any of the inputs (remove a char, add a space, change the value) the ones that I edited get sent to my backend.
I'm using a reducer to store the state. The inputs that I'm using are all just normal react-admin TextInput components.
Here's the code:
const AutoFill = () => {
const [searching, setSearching] = useState(false);
const [error, setError] = useState(false);
const [stateData, setStateData] = useReducer(
(state, newState) => ({ ...state, ...newState }),
{
cep: ' - ',
address: '',
number: '',
neighborhood: '',
city: '',
state: '',
}
);
const FormControl = (event) => {
const { name, value } = event.target;
setStateData({ [name]: value });
};
const SearchControl = (event) => {
const { name, value } = event.target;
setStateData({ [name]: value });
if (value && !value.includes('_')) {
setSearching(true);
setStateData({ state: '...' });
setStateData({ city: '...' });
setStateData({ neighborhood: '...' });
setStateData({ address: '...' });
cep(value.replace('-', '')).then(
(result) => {
setSearching(false);
setError(false);
setStateData({ state: result.state });
setStateData({ city: result.city });
setStateData({ neighborhood: result.neighborhood });
setStateData({ address: result.street });
},
() => {
setSearching(false);
setError(true);
setStateData({ state: '' });
setStateData({ city: '' });
setStateData({ neighborhood: '' });
setStateData({ address: '' });
}
);
}
};
return (
<>
<TextInput
source="cep"
error={error}
value={stateData.cep}
onChange={SearchControl}
/>
<TextInput
source="address"
disabled={searching}
value={stateData.address}
onChange={FormControl}
/>
<TextInput
source="number"
disabled={searching}
value={stateData.number}
onChange={FormControl}
/>
<TextInput
source="neighborhood"
disabled={searching}
value={stateData.neighborhood}
onChange={FormControl}
/>
<TextInput
source="state"
disabled={searching}
value={stateData.state}
onChange={FormControl}
/>
<TextInput
source="city"
disabled={searching}
value={stateData.city}
onChange={FormControl}
/>
</>
);
};
export const Create = (props) => {
return (
<Create {...props}>
<SimpleForm>
<NumberInput label="Value" source="price" />
<AutoFill />
<RichTextInput label="Description" source="description" />
</SimpleForm>
</Create>
);
};
You're going to need to use React Final Form's FormState and Form solutions. Will use snippets of my code for example.
1) Grab the form values
const formState = useFormState();
const form = useForm();
const {
asset_system_parent_id: majorSystem,
classification,
} = formState.values;
2) Setup useEffect that will observe changes to a form field:
useEffect(() => {
const setFluidEnd = async () => {
DO SOMETHING!!!!!
};
if ('Fluid End Maintenance' === classification) {
setFluidEnd();
}
}, [classification, form, notify]);
3) Use form.change (+ form.batch if you need to update multiple inputs)
useEffect(() => {
const setFluidEnd = async () => {
await requestGetList('asset-systems', 'id', 'ASC', 500, {
description: 'Fluid End',
relationship: 'parent',
})
.then(res => {
form.change('asset_system_parent_id', res.data[0].id);
})
.catch(error => {
notify(`System Assets not found`, 'warning');
});
};
if ('Fluid End Maintenance' === classification) {
setFluidEnd();
}
}, [classification, form, notify]);
You can read more about the api here: https://final-form.org/docs/final-form/types/FormApi
Please use this code.
-index.js file
import axios from "axios";
export const setInputValue = (data) => {
return axios.get(`https://www.example.com/profile`)
.then((response) => {
return response.data;
});
};
-component.js
return setInputValue(value).then(() => {
this.setState(() => ({
loading: false
}));
});
...
render(){
return (
...
<input type="text" onClick={e => this.onClick(e)} value={this.state.value}/>
..
)}
...
react-admin.php
...
public function setInputValue(value)
{
try {
$user->set(value);
return response()->json(["result" => "successfully!"]);
} catch (\Exception $e) {
return getErrorResponse($e);
}
}

React TypeScript: Set initial value for input with useRef

The input field displays the value saved in local storage, but I can't edit the value in the input field and I don't know why.
I don't want to use a placeholder as I want to be able to edit the values.
import React, { useRef, useState } from 'react';
const ProfileComponent: React.FC = () => {
let email = useRef<HTMLInputElement>(null);
const saveEmail = () => {
localStorage.setItem('email', email)
}
// tslint:disable-next-line: no-any
const update = (event: any) => {
if (event.target.name === 'email') {
setState({ ...state, email: event.target.value });
} else if (event.target.name === 'fullName') {
setState({ ...state, fullName: event.target.value });
}
};
interface StateInterface {
email: string;
}
const [state, setState] = useState<StateInterface>({
email: localStorage.getItem('email') || '',
});
return (
<input type='text' name='fullName' ref={fullName} onChange={update} value={state.fullName} />
<input type='text' name='email' ref={email} onChange={update} value={state.email} />
<button onClick={saveEmail}></button>
)
}
There are a few issues with the code you have provided
1) You should wrap the DOM elements with React Fragments (<> </>)
2) Instead of setting the type of event as any, you might want to use React.FormEvent<HTMLInputElement>.
3) You should use localStorage.setItem('email', state.email) instead of localStorage.setItem('email', email), since email is a property as part of the state object, thus you will have to reference it in order to access the values.
Here are the full changes below:
interface StateInterface {
email: string;
fullName: string;
}
const ProfileComponent: React.FC = () => {
let email = useRef<HTMLInputElement>(null);
let fullName = useRef<HTMLInputElement>(null);
const [state, setState] = useState<StateInterface>({
email: 'aa#gmail.com' || '',
fullName: 'aa' || '',
});
const saveEmail = () => {
localStorage.setItem('email', state.email)
console.log(state);
}
const update = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.name === 'email') {
setState({ ...state, email: event.target.value });
} else if (event.target.name === 'fullName') {
setState({ ...state, fullName: event.target.value });
}
};
return <>
<input type='text' name='fullName' ref={fullName} onChange={update} value={state.fullName} />
<input type='text' name='email' ref={email} onChange={update} value={state.email} />
<button onClick={saveEmail}>save</button>
</>
}
You have to have an onChange in your input
return (
<input type='text' name='email' ref={email} onChange={e => setState({email: e.target.value})}
value= {state.email} />
<button onClick={saveEmail}></button>
)

Resources