Good afternoon everyone. I have 2 pages: one responsible for displaying List of Users in the table (data comes from fetching), then on Add User button click opens a Modal window with Sign Up form. On submitting this form, data about a new user is sent to an api (fetch POST), then sign up form closes and then the List of Users table is supposed to be updated with a newly added user. I fail to figure out how to correctly perform this update. Simple getUser() call in handleUserFormSubmit function doesn't do the trick (table is not re-rendered). Thanks in advance for any help
// Sign-Up Form Component
import React, { useState, useEffect } from "react";
const SignUpForm = ({
isFormVisible,
setIsFormVisible,
userList,
getUsers,
}) => {
const [usernameList, setUsernameList] = useState([]);
const [username, setUsername] = useState("");
const [usertype, setUsertype] = useState("");
const [password, setPassword] = useState("");
const [verifyPassword, setVerifyPassword] = useState("");
const [isChecked, setIsChecked] = useState(true);
const getUsernameList = () =>
userList.forEach(({ username }) => usernameList.push(username));
useEffect(() => {
getUsernameList();
console.log(usernameList);
}, []);
const addNewUser = async () => {
try {
const response = await fetch(
"http://www.someapi.com/add",
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
username,
usertype,
password,
}),
}
);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error.message);
}
};
const handleUserFormSubmit = (e) => {
e.preventDefault();
addNewUser();
setIsFormVisible(false);
getUsers();
}
};
return (
<>
{isFormVisible && (
<div
className={`${
isFormVisible ? "modal-overlay show-modal" : "modal-overlay"
}`}
>
<div className="sign-up-container">
<div className="sign-up-header-container">
<h2>Sign Up</h2>
<p>Please fill in this form to create an acoount</p>
</div>
<form className="form" onSubmit={(e) => e.preventDefault()}>
<label htmlFor="username">Username</label>{" "}
<br />
<input
type="text"
placeholder="Enter username"
id="username"
name="username"
value={username}
required
onChange={(e) => {
setUsername(e.target.value.toLowerCase());
setIsNameProvided(true);
}}
/>
<br />
<label htmlFor="usertype">User type</label>{" "}
<br />
<select
name="usertype"
id="usertype-select"
required
onChange={(e) => {
setUsertype(e.target.value);
setIsTypeSelected(true);
}}
>
<option value=""></option>
<option value="instructor">instructor</option>
<option value="maintenance">maintenance</option>
</select>
<br />
<label htmlFor="password">Password</label>{" "}
<br />
<input
type="password"
placeholder="Enter password"
id="password"
name="password"
required
value={password}
onCopy={(e) => e.preventDefault()}
onPaste={(e) => e.preventDefault()}
onChange={(e) => {
setPassword(e.target.value);
setIsPasswordProvided(true);
}}
/>
<br />
<label htmlFor="rpassword">Repeat Password</label>{" "}
<br />
<input
type="password"
placeholder="Repeat"
id="rpassword"
name="rpassword"
required
value={verifyPassword}
onCopy={(e) => e.preventDefault()}
onPaste={(e) => e.preventDefault()}
onChange={(e) => {
setVerifyPassword(e.target.value);
setIsConfirmPasswordProvided(true);
}}
/>{" "}
<br />
<input
type="checkbox"
id="remember"
name="remember"
checked={isChecked}
onChange={() => setIsChecked(!isChecked)}
/>
<label htmlFor="remember">Remember me</label>
<p className="terms-privacy">
By creating an account you agree to our{" "}
<a href="#">Terms & Privacy</a>
</p>
<div className="btn-container">
<button
type="button"
className="cancel-btn"
onClick={() => setIsFormVisible(false)}
>
CANCEL
</button>
<button
type="submit"
className="sign-up-btn"
onClick={(e) => handleUserFormSubmit(e)}
>
SIGN UP
</button>
</div>
</form>
</div>
</div>
)}
</>
);
};
export default SignUpForm;
// List Of Users Component:
import React, { useState, useEffect } from "react";
import Loading from "./Loading";
import SignUpForm from "./SignUpForm";
import "./User.css";
const User = () => {
const [userList, setUserList] = useState([]);
const [loading, setLoading] = useState(true);
const [isFormVisible, setIsFormVisible] = useState(false);
const getUsers = async () => {
setLoading(true);
try {
const response = await fetch(
"http://www.someapi.com"
);
const data = await response.json();
setUserList(data);
setLoading(false);
} catch (error) {
console.error(error.message);
setLoading(false);
}
};
useEffect(() => {
getUsers();
}, []);
if (loading) return <Loading />;
return (
<section className="section-user">
<h1>List of Users</h1>
<div className="users-table-container">
<table className="users-table">
<thead>
<tr>
<th>Username</th>
<th>User type</th>
</tr>
</thead>
<tbody>
{userList.map(({ username, userType, hashedPswd }) => (
<tr key={hashedPswd}>
<td>{username}</td>
<td>{userType}</td>
</tr>
))}
</tbody>
</table>
</div>
<button className="add-user-btn" onClick={() => setIsFormVisible(true)}>
Add User
</button>
{isFormVisible && (
<SignUpForm
isFormVisible={isFormVisible}
setIsFormVisible={setIsFormVisible}
userList={userList}
getUsers={getUsers}
/>
)}
</section>
);
};
export default User;
CodePudding user response:
You are directly manipulating a state rather than using setState
. In this case react does not re-render the page even if you manipulate the state. So:
// wrong
const getUsernameList = () =>
userList.forEach(({ username }) => usernameList.push(username));
// correct
const getUsernameList = () => {
const list = userList.map(user => user.username)
setUsernameList(list)
}
*Edit: I think you are not saving your response data after creating a new user
CodePudding user response:
In User
component add
useEffect(() => {
if (isFormVisible) getUsers();
}, [isFormVisible]);