Reputation: 848
I have and update user page. There exists a simple form based on functional component. I use hooks in order to work with state and input params. Default params(which can be changed) I get from redux store(I fetch them in useEffect). After page load store changes, bot hooks does not update necessary properties in form and there are empty inputs. How can I supposed, that after store update hookk would update state, but no. How can I solve this problem?
component:
const EditUserPage: React.FunctionComponent<Props> = () => {
const dispatch = useDispatch();
const history = useHistory();
const {profileId} = useParams<UrlParams>();
useEffect(() => {
dispatch(getRolesList());
console.log("URL PARAM=", profileId)
dispatch(getProfileById(parseInt(profileId)));
}, []);
const isEmailDuplicated: boolean = useSelector(getEmailDuplicated);
const rolesList: Array<PlainObject> = useSelector(userRolesList);
const contetType: string = useSelector(adminContentType);
const userProfileData: PlainObject = useSelector(selectedUserProfile);
const [startDate, setStartDate] = useState<Date>(new Date());
const [firstName, setFirstName] = useState<string>(userProfileData.firstName);
const [lastName, setLastName] = useState<string>(userProfileData.lastName ? userProfileData.lastName : "");
const [role, setRole] = useState<string>(userProfileData.user && userProfileData.user.roles[0].name);
const [gender, setGender] = useState<string>(userProfileData.gender ? userProfileData.gender : "");
const [address, setAddress] = useState<string>(userProfileData.address ? userProfileData.address : "");
const [phone, setPhone] = useState<string>(userProfileData.telephone ? userProfileData.telephone : "");
const [office, setOffice] = useState<string>(userProfileData.office ? userProfileData.office : "");
const [socialNumber, setSocialNumber] = useState<string>(userProfileData.socialNumber ? userProfileData.socialNumber : "");
const [about, setAbout] = useState<string>(userProfileData.about ? userProfileData.about : "");
const [login, setLogin] = useState<string>(userProfileData.email ? userProfileData.email : "");
const roleDropdownOptions = rolesList && rolesList.map((role) => {
console.log("?????",userProfileData)
return {
key: role.id,
text: role.name.toLowerCase(),
value: role.name,
}
})
//validate email
const mailRegex = new RegExp(/^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/g);
const isMailValid = login && mailRegex.test(login);
//validate phone number
const phoneRegex = new RegExp(/^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s./0-9]*$/g)
const isPhoneValid = phone && phoneRegex.test(phone);
const handleSubmit = (event: { preventDefault: () => void; }) => {
const dateFormat = require("dateformat");
event.preventDefault();
userProfileData["firstName"] = firstName;
userProfileData["lastName"] = lastName;
userProfileData["email"] = login;
userProfileData["telephone"] = phone;
userProfileData["about"] = about;
userProfileData["office"] = office;
userProfileData["address"] = address;
userProfileData["socialNumber"] = socialNumber;
userProfileData["dateOfBirth"] = dateFormat(startDate, "yyyy-mm-dd");
userProfileData["gender"] = gender;
const promise = new Promise(() => {
return dispatch(updateProfile(userProfileData));
})
promise
.then(() => history.push("/admin"))
.then(() => {
if (contetType === adminContentTypes.PERSONAL) {
dispatch(getPersonalProfiles());
} else {
dispatch(getPatientProfiles());
}
})
}
return (
<Fragment>
<Header as="h1">
EDIT USER
</Header>
<Divider/>
<Form onSubmit={handleSubmit}>
{
isEmailDuplicated &&
<Message
negative={true}
header="Account already exists"
content="An account already exists for this email address, please log in or confirm your email address is correct"
/>
}
<Form.Group widths="equal">
<Form.Input
label="First name"
name="firstName"
value={firstName}
required={true}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setFirstName(e.target.value)}
/>
<Form.Input
label="Last name"
name="lastName"
value={lastName}
required={true}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setLastName(e.target.value)}
/>
<Form.Input
label="Email"
name="login"
required={true}
value={login}
error={!isMailValid && login ? {
content: "Please enter a valid email address",
pointing: "below",
} : false}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setLogin(e.target.value)}
/>
</Form.Group>
<Divider hidden/>
<Form.Group>
<Form.Select
width={4}
placeholder="User role"
label="User role"
name="user_role"
selection
options={roleDropdownOptions}
value={role}
required={true}
onChange={(event: React.ChangeEvent<HTMLSelectElement>, data: PlainObject) => {
event.preventDefault();
setRole(data.value);
}}
/>
<Form.Select
width={4}
value={gender}
label="Gender"
name="gender"
selection
options={options}
required={true}
onChange={(event: React.ChangeEvent<HTMLSelectElement>, data: PlainObject) => setGender(data.value)}
/>
<Form.Input
width={4}
label="Office"
name="office"
value={office}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setOffice(e.target.value)}
/>
<div style={{"paddingLeft": "7px", "paddingRight": "7px"}}>
<label>
Date of birth
</label>
<br/>
<DatePicker
selected={startDate}
onChange={(date: Date) => {
setStartDate(date)
}}
peekNextMonth
showMonthDropdown
showYearDropdown
dropdownMode="select"
/>
</div>
</Form.Group>
<Divider hidden/>
<Form.Group>
<Form.Input
width={4}
label="Address"
name="address"
value={address}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setAddress(e.target.value)}
/>
<Form.Input
width={4}
label="Phone number"
name="telephone"
value={phone}
required={true}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setPhone(e.target.value)}
error={!isPhoneValid && phone ? {
content: "Please enter a valid phone number",
pointing: "below",
} : false}
/>
<Form.TextArea
label="About"
value={about}
width={8}
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>, data: PlainObject) => setAbout(data.value)}
/>
</Form.Group>
<Divider hidden/>
<Form.Group widths="equal">
<Form.Input
label="Social number"
name="socialNumber"
value={socialNumber}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSocialNumber(e.target.value)}
/>
</Form.Group>
<Divider hidden/>
<Button
floated="right"
size="medium"
onClick={() => history.push("/admin")}
>
Back
</Button>
<Button
color="blue"
floated="right"
size="medium"
disabled={!isMailValid || !isPhoneValid}
>
Save
</Button>
</Form>
</Fragment>
);
}
export default EditUserPage;
Upvotes: 0
Views: 121
Reputation: 106
I think you'll want another useEffect
that watches for changes on userProfileData
.
Right now you're initializing all your hooks state variables with the userProfileData
, but on the first pass that data is empty.
When the store updates the userProfileData
value should change but this component isn't set up to do anything with it.
const [firstName, setFirstName] = useState<string>(userProfileData.firstName);
If you also had a hook below that calls the set
callbacks it should update once the store does.
useEffect(() => {
setFirstName(userProfileData.firstName);
}, [userProfileData])'
This might cause issues if you run into a scenario where
If that instance is a possibility you could add logic at the beginning of the useEffect
to not update the field if it's already been updated.
Upvotes: 2