Not changing the specified data on update-action - reactjs

I have an Edit Form in which i can update an already existing element of specified ID.
Let's say im editing this character:
{
"name": "Walter White",
"birthday": "1963-01-07",
"img": "https://upload.wikimedia.org/wikipedia/en/0/03/Walter_White_S5B.png",
"status": "Alive",
"appereance": [1, 2, 3],
"id": 1
}
I want to change the name,birthday,image and status. And i already did that. But I want the apperance array to remain the same. Although, after updating the data, the apperance is being erased.
Does anyone know, what can I do so that the apperance array won't change?
My EditForm code:
const UserEditForm = () => {
let { id } = useParams();
const { user } = useSelector((state) => state.user);
const [state, setState] = useState({
name: "",
birthday: "",
img: "",
status: "",
// appereance: ?????
});
const [error, setError] = useState("");
let history = useHistory();
let dispatch = useDispatch();
const { name, birthday, img, status, apperance } = state;
useEffect(() => {
dispatch(getSingleUser(id));
}, []);
useEffect(() => {
if (user) {
setState({ ...user });
}
}, [user]);
const handleInputChange = (e) => {
let { name, value } = e.target;
setState({ ...state, [name]: value });
};
const handleSubmit = () => {
dispatch(updateUser(state, id));
history.push("/");
setError("");
};
return (
<div>
<Button
style={{ width: "100px", marginTop: "20px" }}
variant="contained"
color="secondary"
type="button"
onClick={() => history.push("/")}
>
Go Back
</Button>
<h2>Edit User</h2>
{error && <h3 style={{ color: "red" }}>{error}</h3>}
<form onSubmit={handleSubmit}>
<TextField
id="standard-basic"
label="Name"
value={name || ""}
name="name"
type="text"
required
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
name="birthday"
value={birthday || ""}
type="date"
required
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
label="img"
value={img || ""}
name="img"
type="url"
required
onChange={handleInputChange}
/>
<select
id="standard-basic"
label="status"
value={status || ""}
name="status"
onChange={handleInputChange}
>
<option value={""}>Brak informacji</option>
<option value={"Alive"}>Alive</option>
<option value={"Dead"}>Dead</option>
</select>
<Button
style={{ width: "100px" }}
variant="contained"
color="primary"
type="submit"
onChange={handleInputChange}
>
Update
</Button>
</form>
</div>
);
};
EDIT ADDED REDUCER
const fetchState = {
users: [],
user: {},
};
export const userReducer = (state = fetchState, { type, payload }) => {
switch (type) {
case USERS_FETCH:
return { ...state, users: payload };
case ADD_USER:
return { ...state, users: [...state.users, payload] };
case UPDATE_USER:
return { ...state, users: [...state.users, payload] };
case GET_SINGLE_USER:
return {
...state,
user: payload,
};
default:
return state;
}
};
export const selectedUserReducer = (state = {}, { type, payload }) => {
switch (type) {
case GET_USER:
return { ...state, ...payload };
default:
return state;
}
};

Related

My react typescript code does not render data from child to parent component in one go

interface Props {
handleNext2: () => void;
handleprevious2: () => void;
visible2: boolean;
onFinish: (values: any) => void;
}
const userRef = useRef<HTMLInputElement>();
const [moNumber, setMoNumber] = useState<string>("");
const [validMoNumber, setValidMoNumber] = useState<boolean>(false);
const [moNumberW, setMoNumberW] = useState<string>("");
const [validdMoNumberW, setValiddMoNumberW] = useState<boolean>(false);
const [lLine, setLline] = useState<string>("");
const [validLline, setValidLline] = useState<boolean>(false);
const [email, setEmail] = useState<string>("");
const [web, setWeb] = useState<string>("");
useEffect(() => {
userRef.current?.focus();
}, []);
useEffect(() => {
const result: boolean = MNO.test(moNumber);
setValidMoNumber(result);
}, [moNumber]);
useEffect(() => {
const result: boolean = MNOW.test(moNumberW);
setValiddMoNumberW(result);
}, [moNumberW]);
useEffect(() => {
const result = L_LINE.test(lLine);
setValidLline(result);
}, [lLine]);
return (
<Modal
title="Sign Up"
open={visible2}
cancelButtonProps={{ style: { display: "none" } }}
okButtonProps={{ style: { display: "none" } }}
// onOk={handleNext2}
// okText="Next"
// onCancel={handleprevious2}
// cancelText="Previous"
>
<div className="header">
<h1>Contact Information</h1>
<div className="text-container">
<p className="text-1">
This Information is what your prospective clients will be using to
get in touch with you. Make sure its accurate
</p>
</div>
<h2>"Greate coaches prioratize communication"</h2>
</div>
<Form
className="form"
form={form2}
name="contact"
onFinish={handleFinish2}
>
<div className="input-controller">
<div className="input-with-label">
<h3>Mobile No</h3>
<Form.Item
className="form-item"
name="moNo"
hasFeedback
rules={[
{
// required: true,
message: "Please input your mobile no",
},
{
validator: (_, value) => {
if (!validMoNumber && value) {
return Promise.reject("Invalid mobile no");
}
if (!value) {
return Promise.resolve();
}
return Promise.resolve();
},
},
]}
>
<Input
className="inputs"
ref={userRef as any}
value={moNumber}
onChange={(e) => {
setMoNumber(e.target.value);
}}
/>
</Form.Item>
</div>
<div className="input-with-label">
<h3>WhatssApp NO</h3>
<Form.Item
className="form-item"
name="WhatsApp"
hasFeedback
rules={[
{
validator: (_, value) => {
if (!validdMoNumberW && value) {
return Promise.reject("Invalid last name");
}
if (!value) {
return Promise.resolve();
}
return Promise.resolve();
},
},
]}
>
<Input
value={moNumberW}
className="inputs"
onChange={(e) => {
setMoNumberW(e.target.value);
}}
/>
</Form.Item>
</div>
</div>
<div className="input-controller">
<div className="input-with-label">
<h3>LandLine</h3>
<Form.Item
className="form-item"
name="LandLine"
rules={[
{
validator: (_, value) => {
if (!validLline && value) {
return Promise.reject("Invalid password");
}
if (!value) {
return Promise.resolve();
}
return Promise.resolve();
},
},
]}
hasFeedback
>
<Input
onChange={(e) => setLline(e.target.value)}
className="inputs"
value={lLine}
/>
</Form.Item>
</div>
<div className="input-with-label">
<h3>E-mail</h3>
<Form.Item
className="form-item"
name="Email"
rules={[
{
type: "email",
message: "The input is not valid E-mail!",
},
{
// required: true,
message: "Please input your E-mail!",
},
]}
>
<Input
className="inputs"
onChange={(e) => setEmail(e.target.value)}
value={email}
/>
</Form.Item>
</div>
</div>
<h3>Website</h3>
<Form.Item className="form-item" name="Website" hasFeedback>
<Input
className="inputs"
id="website"
onChange={(e) => setWeb(e.target.value)}
value={web}
/>
</Form.Item>
<Form.Item>
<Button style={{ width: "100%" }} type="primary" htmlType="submit">
Next
</Button>
</Form.Item>
<Form.Item>
<Button
style={{ width: "100%", backgroundColor: "red" }}
type="primary"
onClick={handleprevious2}
>
Cancel
</Button>
</Form.Item>
</Form>
</Modal>
);
};
export default PopUp2;
I use above code as a child component.onFinishFunction is used to send data to the parent.
This is a parent.
onst HeadCoachSignUp: React.FC = () => {
const [form] = Form.useForm();
// ---------------------------To send data------------------------------
//-------For all signup data-------------------------
const [firstName, setFName] = useState<string>("");
const [lastName, setLName] = useState<string>("");
const [pwd, setPwd] = useState<string>("");
const [address, setAddress] = useState<string>("");
const [nicNumber, setNicNo] = useState<string>("");
const [Gender, setGender] = useState<string>("");
const [moNumber, setMoNumber] = useState<string>("");
const [moNumberWhatsApp, setMoNumberW] = useState<string>("");
const [landLine, setLline] = useState<string>("");
const [Email, setEmail] = useState<string>("");
const [webSite, setWeb] = useState<string>("");
const [formData1, setFormData1] = useState<FormData | any>({});
const [formData2, setFormData2] = useState<FormData | any>({});
const [certificates, setCertificates] = useState<FormData | any>({});
const [Athletics, setAthletics] = useState<FormData | any>({});
const [experiences, setExperiences] = useState<FormData | any>({});
const [formData6, setFormData6] = useState<FormData | any>({});
const [formData7, setFormData7] = useState<FormData | any>({});
const [formData8, setFormData8] = useState<FormData | any>({});
const handleFormFinish1 = (values: any) => {
setFormData1(values);
};
const handleFormFinish2 = (values: any) => {
setFormData2(values);
console.log(moNumber, moNumberWhatsApp, landLine, Email, webSite);
axios
.post("http://localhost:5001/api/headcoach/signup", {
moNumber: moNumber,
moNumberW: moNumberWhatsApp,
lLine: landLine,
email: Email,
webSite: webSite,
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error, error.response);
});
};
useEffect(() => {
const { fName, lName, password, Address, nicNo, gender } = formData1;
const { moNo, WhatsApp, LandLine, Email, Website } = formData2;
const { des2 } = formData6;
const { sbscribe } = formData8;
setFName(fName);
setLName(lName);
setPwd(password);
setAddress(Address);
setNicNo(nicNo);
setGender(gender);
setMoNumber(moNo);
setMoNumberW(WhatsApp);
setLline(LandLine);
setEmail(Email);
setWeb(Website);
setPackageDescription(formData6);
// setRate1(rate1);
// setRate2(rate2);
// setMinONumber1(minONumber1);
// setMinONumber2(minONumber2);
// setDiscount1(discount1);
// setDiscount2(discount2);
// setFrom1(from1);
// setTo1(to1);
// setFrom2(from2);
// setTo2(to2);
// setDes1(des1);
// setDes2(des2);
setSubscribe(sbscribe);
});
const handleNext2 = () => {
form
.validateFields()
.then(() => {
form.resetFields();
setVisible2(!visible2);
setVisible3(!visible3);
})
.catch((info) => {
console.log("Validate Failed:", info);
});
};
return (
<div
style={{
display: "flex",
justifyContent: "center",
marginTop: "20%",
}}
>
{/* <Test /> */}
<Button type="primary" onClick={showModal}>
SignUp
</Button>
<PopUp1
handleNext1={handleNext1}
handleCancel1={handleCancel1}
visible1={visible1}
onFinish={handleFormFinish1}
/>
<PopUp2
onFinish={handleFormFinish2}
handleNext2={handleNext2}
handleprevious2={handleprevious2}
visible2={visible2}
/>
<PopUp3
visible3={visible3}
handleNext3={handleNext3}
handleprevious3={handleprevious3}
onFinish={handleFormFinish3}
/>
<PopUp4
visible4={visible4}
handleNext4={handleNext4}
handleprevious4={handleprevious4}
onFinish={handleFormFinish4}
/>
<PopUp5
visible5={visible5}
handleNext5={handleNext5}
handleprevious5={handleprevious5}
onFinish={handleFormFinish5}
/>
<PopUp6
visible6={visible6}
handleNext6={handleNext6}
handleprevious6={handleprevious6}
onFinish={handleFormFinish6}
/>
<PopUp7
visible7={visible7}
handleNext7={handleNext7}
handleprevious7={handleprevious7}
/>
<PopUp8
visible8={visible8}
handleFinish={handleFinish}
handleprevious8={handleprevious8}
onFinish={handleFormFinish8}
/>
</div>
);
};
export default HeadCoachSignUp;
. This is a full code. But I reduced some parts. So please give me a solution to take data from the child to parent component. When I submit the form, It will not be updated in the parent. It prints values as undefined. If again submit the same form with same data as second submit, It will take the data to parent and sends to console, why is that?

in Reactjs, this.props loses fields which don't belong to the table on which data added or edited

I'm new to ReactJs. I've an getResorts API which returns
data(resortId,name,address,phone,details,placeId,city,state,country) from
1)resort(resortId,name,address,phone,details,placeId) and
2) place table(placeId,city,state,country)
This data from API, I'm binding it to a grid as shown here
I've a separate API to get places data only from places table to bind the dropdowns -city,state and country in modal dialog for add/edit option and pass the selected city Id as the placeId while adding or editing resort as shown here
In ComponentDidUpdate(), after a succesful add or edit of a resort, the this.props has all the resorts of bound to the grid but the record for the updated resort or newly added resort has the city,state and country parts missing even though the resort data(resortId,name,phone,details,placeId) has been successfully added or edited, so my grid look like this after an insert or edit city,state,country missing for record updated or added in this.props
This might be due to the city,state,country not being part of the resort table, how to fix this - the this.props after successful add or edit? How can we know the action status type of saga function successfully executed in ComponentDidUpdate?
CompnentDidUpdate in resort-list.js
componentDidUpdate(prevProps, prevState, snapshot) {
const { resorts } = this.props;
if (!isEmpty(resorts) && size(prevProps.resorts) !== size(resorts)) {
this.setState({ resorts: {}, isEdit: false });
}
}
componentDidMount() {
const { resorts, onGetResorts } = this.props;
const {places, onGetPlaces}=this.props;
if (resorts && !resorts.length) {
onGetResorts();
}
this.setState({ resorts });
if (places && !places.length) {
onGetPlaces();
}
this.setState({ places });
}
<div className="table-responsive">
<BootstrapTable
{...toolkitprops.baseProps}
{...paginationTableProps}
selectRow={selectRow}
defaultSorted={defaultSorted}
classes={
"table align-middle table-nowrap table-hover"
}
bordered={false}
striped={false}
responsive
ref={this.node}
/>
<Modal
isOpen={this.state.modal}
className={this.props.className}
>
<ModalHeader
toggle={this.toggle}
tag="h4"
>
{!!isEdit ? "Edit Resort" : "Add Resort"}
</ModalHeader>
<ModalBody>
<Formik
enableReinitialize={true}
initialValues={{
name:
(resort && resort.name) || "",
address:
(resort && resort.address) ||
"",
phone:
(resort && resort.phone) ||
"",
details:
(resort && resort.details) ||
"",
placeId: (resort && resort.placeId) ||
"",
city:
(resort && resort.city) || "",
state:
(resort && resort.state) || "",
country:
(resort && resort.country) ||
"",
}}
validationSchema={Yup.object().shape({
name: Yup.string().required(
"Please Enter Resort Name"
),
phone: Yup.number().required(
"Please Enter Phone"
),
address: Yup.string().required(
"Please Enter Address"
),
details: Yup.string().required(
"Please Enter Details"
),
/* tags:
Yup.array().required(
"Please Select Tags"
),*/
city:
Yup.string().required(
"Please Enter City"
),
state:
Yup.string().required(
"Please Enter State"
),
country:
Yup.string().required(
"Please Enter Country"
),
})}
onSubmit={values => {
console.log(">>>values>>>>> "+JSON.stringify(values));
if (isEdit) {
const updateResort = {
id: resort.id,
name: values.name,
address: values.address,
phone: values.phone,
details: values.details,
// placeId:updatePlaceId.placeId,
placeId:this.state.placeId,
city: values.city,
state: values.state,
country: values.country,
};
console.log("----update----- "+JSON.stringify(updateResort))
// update user
onUpdateResort(updateResort);
} else {
// const newPlaceId=places.filter(x=>x.city===values["city"]);
const newResort = {
// id: values["id"],
name: values["name"],
address: values["address"],
phone: values["phone"],
details: values["details"],
placeId:this.state.placeId,
// placeId:newPlaceId.placeId
city: values["city"],
state: values["state"],
country: values["country"],
};
console.log("-----new---- "+JSON.stringify(newResort))
// save new resort
onAddNewResort(newResort);
}
this.setState({ selectedResort: null });
this.toggle();
}}
>
{({ errors, status, touched,setFieldValue,handleChange}) => (
<Form>
<Row>
<Col className="col-12">
<div className="mb-3">
<Label className="form-label">
Resort Name
</Label>
<Field
name="name"
type="text"
className={
"form-control" +
(errors.name &&
touched.name
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="name"
component="div"
className="invalid-feedback"
/>
</div>
<div className="mb-3">
<Label className="form-label">
Address
</Label>
<Field
name="address"
type="text"
className={
"form-control" +
(errors.address &&
touched.address
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="address"
component="div"
className="invalid-feedback"
/>
</div>
<div className="mb-3">
<Label className="form-label">
Phone
</Label>
<Field
name="phone"
type="tel"
className={
"form-control" +
(errors.phone &&
touched.phone
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="phone"
component="div"
className="invalid-feedback"
/>
</div>
<div className="mb-3">
<Label className="form-label">
Details
</Label>
<Field
name="details"
type="text"
className={
"form-control" +
(errors.details &&
touched.details
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="details"
component="div"
className="invalid-feedback"
/>
</div>
<div className="mb-3">
<Label className="form-label">
City
</Label>
<Field
onChange={(e) => {
handleChange(e);
let selectedGeo=places.filter((x) => x.city === e.target.value)
if(selectedGeo.length>0)
{
this.setState({placeId:selectedGeo[0].id});
setFieldValue("state", selectedGeo[0].state)
setFieldValue("country", selectedGeo[0].country)
}
}}
type="text"
name="city"
list="datalistCity"
className={
"form-control" +
(errors.city &&
touched.city
? " is-invalid"
: "")
}
multiple={false}
/>
<datalist id="datalistCity">
{
places.map((place) => {
return (
<option
value={place.city}
key={place.id}
>
</option>
);
})}
</datalist>
<ErrorMessage
name="city"
component="div"
className="invalid-feedback"
/>
</div>
<div className="mb-3">
<Label className="form-label">
State
</Label>
<Field
name="state" disabled
type="text"
className="form-control"
/>
<ErrorMessage
name="state"
component="div"
className="invalid-feedback"
/>
</div>
<div className="mb-3">
<Label className="form-label">
Country
</Label>
<Field
type="text"
name="country"
disabled
className="form-control"
/>
<ErrorMessage
name="country"
component="div"
className="invalid-feedback"
/>
</div>
</Col>
</Row>
<Row>
<Col>
<div className="text-end">
<button
type="submit"
className="btn btn-success save-resort"
>
Save
</button>
</div>
</Col>
</Row>
</Form>
)}
</Formik>
</ModalBody>
</Modal>
</div>
ResortsList.propTypes = {
resorts: PropTypes.array,
places:PropTypes.array,
className: PropTypes.any,
onGetResorts: PropTypes.func,
onGetPlaces: PropTypes.func,
onAddNewResort: PropTypes.func,
onDeleteResort: PropTypes.func,
onUpdateResort: PropTypes.func,
};
const mapStateToProps = ({ resorts,places }) => ({
resorts: resorts.resorts,
places:places.places
});
const mapDispatchToProps = dispatch => ({
onGetResorts: () => dispatch(getResorts()),
onGetPlaces: () => store.dispatch(getPlaces()),
onAddNewResort: resort => dispatch(addNewResort(resort)),
onUpdateResort: resort => dispatch(updateResort(resort)),
onDeleteResort: resort => dispatch(deleteResort(resort)),
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(withRouter(ResortsList));
In ResortSaga,
const getUserName = () => {
if (localStorage.getItem("authUser")) {
const obj = JSON.parse(localStorage.getItem("authUser"))
return obj;
}
}
function* fetchResorts() {
try {
let obj = getUserName();
const response = yield call(getResorts, obj.accessToken)
console.log("resort list ---- "+JSON.stringify(response))
yield put(getResortsSuccess(response))
} catch (error) {
yield put(getResortsFail(error))
}
}
function* fetchResortDetails({id}) {
try {
const obj = JSON.parse(localStorage.getItem("authUser"));
const response = yield call(getResortDetails,id, obj)
yield put(getResortDetailsSuccess(response))
} catch (error) {
yield put(getResortDetailsFail(error))
}
}
function* onAddNewResort({ payload: resort }) {
try {
let obj = getUserName();
const response = yield call(addNewResort, resort, obj.accessToken)
console.log("------- "+JSON.stringify(response))
yield put(addResortSuccess(response))
} catch (error) {
yield put(addResortFail(error))
}
}
function* onUpdateResort({ payload: resort }) {
try {
//const obj = JSON.parse(localStorage.getItem("authUser"));
console.log("Saga..... edit >>>. "+JSON.stringify(resort))
let obj = getUserName();
const response = yield call(updateResort, resort, obj.accessToken)
yield put(updateResortSuccess(response))
} catch (error) {
yield put(updateResortFail(error))
}
}
function* onDeleteResort({ payload: resort }) {
try {
let obj = getUserName();
console.log("Saga..... delete >>>. "+JSON.stringify(resort))
const response = yield call(deleteResort, resort, obj.accessToken)
yield put(deleteResortSuccess(response))
} catch (error) {
yield put(deleteResortFail(error))
}
}
function* resortsSaga() {
yield takeEvery(GET_RESORTS, fetchResorts)
yield takeEvery(GET_RESORT_DETAILS, fetchResortDetails)
yield takeEvery(ADD_NEW_RESORT, onAddNewResort)
yield takeEvery(UPDATE_RESORT, onUpdateResort)
yield takeEvery(DELETE_RESORT, onDeleteResort)
}
export default resortsSaga
In action.js
import {
GET_RESORT_DETAILS,
GET_RESORT_DETAILS_FAIL,
GET_RESORT_DETAILS_SUCCESS,
GET_RESORTS,
GET_RESORTS_FAIL,
GET_RESORTS_SUCCESS,
ADD_NEW_RESORT,
ADD_RESORT_SUCCESS,
ADD_RESORT_FAIL,
UPDATE_RESORT,
UPDATE_RESORT_SUCCESS,
UPDATE_RESORT_FAIL,
DELETE_RESORT,
DELETE_RESORT_SUCCESS,
DELETE_RESORT_FAIL,
} from "./actionTypes"
export const getResorts = () => ({
type: GET_RESORTS,
})
export const getResortsSuccess = resorts => ({
type: GET_RESORTS_SUCCESS,
payload: resorts,
})
export const getResortsFail = error => ({
type: GET_RESORTS_FAIL,
payload: error,
})
export const getResortDetails = id => ({
type: GET_RESORT_DETAILS,
id,
})
export const getResortDetailsSuccess = resortDetails => ({
type: GET_RESORT_DETAILS_SUCCESS,
payload: resortDetails,
})
export const getResortDetailsFail = error => ({
type: GET_RESORT_DETAILS_FAIL,
payload: error,
})
export const addNewResort = resort => ({
type: ADD_NEW_RESORT,
payload: resort,
})
export const addResortSuccess = resort => ({
type: ADD_RESORT_SUCCESS,
payload: resort,
})
export const addResortFail = error => ({
type: ADD_RESORT_FAIL,
payload: error,
})
export const updateResort = resort => ({
type: UPDATE_RESORT,
payload: resort,
})
export const updateResortSuccess = resort => ({
type: UPDATE_RESORT_SUCCESS,
payload: resort,
})
export const updateResortFail = error => ({
type: UPDATE_RESORT_FAIL,
payload: error,
})
export const deleteResort = resort => ({
type: DELETE_RESORT,
payload: resort,
})
export const deleteResortSuccess = resort => ({
type: DELETE_RESORT_SUCCESS,
payload: resort,
})
export const deleteResortFail = error => ({
type: DELETE_RESORT_FAIL,
payload: error,
})
In actionType.js
/* USERS */
export const GET_RESORTS = "GET_RESORTS"
export const GET_RESORTS_SUCCESS = "GET_RESORTS_SUCCESS"
export const GET_RESORTS_FAIL = "GET_RESORTS_FAIL"
/* USERS PROFILE */
export const GET_RESORT_DETAILS = "GET_RESORT_DETAILS"
export const GET_RESORT_DETAILS_SUCCESS = "GET_RESORT_DETAILS_SUCCESS"
export const GET_RESORT_DETAILS_FAIL = "GET_RESORT_DETAILS_FAIL"
export const ADD_NEW_RESORT = "ADD_NEW_RESORT"
export const ADD_RESORT_SUCCESS = "ADD_RESORT_SUCCESS"
export const ADD_RESORT_FAIL = "ADD_RESORT_FAIL"
export const UPDATE_RESORT = "UPDATE_RESORT"
export const UPDATE_RESORT_SUCCESS = "UPDATE_RESORT_SUCCESS"
export const UPDATE_RESORT_FAIL = "UPDATE_RESORT_FAIL"
export const DELETE_RESORT = "DELETE_RESORT"
export const DELETE_RESORT_SUCCESS = "DELETE_RESORT_SUCCESS"
export const DELETE_RESORT_FAIL = "DELETE_RESORT_FAIL"
In reducer.js
import {
GET_RESORT_DETAILS,
GET_RESORT_DETAILS_FAIL,
GET_RESORT_DETAILS_SUCCESS,
GET_RESORTS,
GET_RESORTS_FAIL,
GET_RESORTS_SUCCESS,
ADD_NEW_RESORT,
ADD_RESORT_SUCCESS,
ADD_RESORT_FAIL,
UPDATE_RESORT,
UPDATE_RESORT_SUCCESS,
UPDATE_RESORT_FAIL,
DELETE_RESORT,
DELETE_RESORT_SUCCESS,
DELETE_RESORT_FAIL,
} from "./actionTypes"
const INIT_STATE = {
resorts: [],
resortDetails: {},
error: {},
}
const resorts = (state = INIT_STATE, action) => {
switch (action.type) {
case GET_RESORTS_SUCCESS:
return {
...state,
resorts: action.payload,
}
case GET_RESORTS_FAIL:
return {
...state,
error: action.payload,
}
case ADD_RESORT_SUCCESS:
return {
...state,
resorts: [...state.resorts, action.payload],
}
case ADD_RESORT_FAIL:
return {
...state,
error: action.payload,
}
case GET_RESORT_DETAILS_SUCCESS:
return {
...state,
resortDetails: action.payload,
}
case GET_RESORT_DETAILS:
return {
...state,
resortDetails: action.payload,
}
case UPDATE_RESORT_SUCCESS:
return {
...state,
resorts: state.resorts.map(resort =>
resort.id.toString() === action.payload.id.toString()
? { resort, ...action.payload }
: resort
),
}
case UPDATE_RESORT_FAIL:
return {
...state,
error: action.payload,
}
case DELETE_RESORT_SUCCESS:
return {
...state,
resorts: state.resorts.filter(
resort => resort.id.toString() !== action.payload.id.toString()
),
}
case DELETE_RESORT_FAIL:
return {
...state,
error: action.payload,
}
case GET_RESORT_DETAILS_FAIL:
return {
...state,
error: action.payload,
}
default:
return state
}
}
export default resorts
So, how do I get type success status from saga for add/edit in ComponentDidMount, so I can add the missing city,state,country manually to the this.props for the resort that was just modified based on resortId? So, when data from this.props get rendered to the grid after add/edit, the places part of the data - city,state and country aren't missing for the resort added or modified from the this.props and the grid.
In Watch, resort before editin this.props and here in watch, city,state,country removed in this.props after successful edit

After editing data, redux cannot read id

i have a problem.
I use a form to edit my data, then when i want to see edited data, i get an ×
TypeError: Cannot read properties of undefined (reading 'id')
Pointing at my
{users &&
users.map((user) => {
return (
<div key={user.id}>
<Link to={`users/${user.id}`}> {user.name} </Link>
</div>
);
})}
Which is used to display data.
After refreshing the site (F5) it works, so i assume that the redux has problem with reading edited data for the first time, altough it do work with adding new data. anyone know what i can do?
My UserEditForm:
const UserEditForm = () => {
let { id } = useParams();
const { user } = useSelector((state) => state.user);
const [state, setState] = useState({
name: "",
birthday: "",
img: "",
});
const [error, setError] = useState("");
console.log(id);
let history = useHistory();
let dispatch = useDispatch();
const { name, birthday, img } = state;
useEffect(() => {
dispatch(getSingleUser(id));
}, []);
useEffect(() => {
if (user) {
setState({ ...user });
}
}, [user]);
const handleInputChange = (e) => {
let { name, value } = e.target;
setState({ ...state, [name]: value });
};
const handleSubmit = (e) => {
dispatch(updateUser(state, id));
history.push("/");
setError("");
};
return (
<div>
<Button
style={{ width: "100px", marginTop: "20px" }}
variant="contained"
color="secondary"
onClick={() => history.push("/")}
>
Go Back
</Button>
<h2>Edit User</h2>
{error && <h3 style={{ color: "red" }}>{error}</h3>}
<form noValidate autoComplete="off" onSubmit={handleSubmit}>
<TextField
id="standard-basic"
label="Name"
value={name || ""}
name="name"
type="text"
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
label="birthday"
name="birthday"
value={birthday || ""}
type="birthday"
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
label="img"
value={img || ""}
name="img"
type="number"
onChange={handleInputChange}
/>
<Button
style={{ width: "100px" }}
variant="contained"
color="primary"
type="submit"
onChange={handleInputChange}
>
Update
</Button>
</form>
</div>
);
};
export default UserEditForm;
My UserList component:
const UserList = ({ users, history }) => {
const dispatch = useDispatch();
const fetchUsers = async () => {
const response = await axios
.get("http://localhost:3000/characters")
.catch((err) => {
console.log("Err: ", err);
});
dispatch(setUsers(response.data));
};
useEffect(() => {
fetchUsers();
}, []);
console.log(users);
return (
<div>
<button onClick={() => history.goBack()}>...back</button>
<li>
<Link to="/user/add">Add Users</Link>
</li>
{users &&
users.map((user) => {
return (
<div key={user.id}>
<Link to={`users/${user.id}`}> {user.name} </Link>
</div>
);
})}
</div>
);
};
const mapStateToProps = (state) => {
return {
users: state.allUsers.users,
};
};
export default connect(mapStateToProps, null)(UserList);

Editing data in redux, but leaving some values unchanged

I have an Edit Form in which i can update an already existing element of specified ID.
Let's say im editing this character:
{
"name": "Walter White",
"birthday": "1963-01-07",
"img": "https://upload.wikimedia.org/wikipedia/en/0/03/Walter_White_S5B.png",
"status": "Alive",
"appereance": [1, 2, 3],
"id": 1
}
I want to change the name,birthday,image and status. And i already did that. But I want the apperance array to remain the same. Although, after updating the data, the apperance is being erased.
Does anyone know, what can I do so that the apperance array won't change?
My EditForm code:
const UserEditForm = () => {
let { id } = useParams();
const { user } = useSelector((state) => state.user);
const [state, setState] = useState({
name: "",
birthday: "",
img: "",
status: "",
// appereance: ?????
});
const [error, setError] = useState("");
let history = useHistory();
let dispatch = useDispatch();
const { name, birthday, img, status, apperance } = state;
useEffect(() => {
dispatch(getSingleUser(id));
}, []);
useEffect(() => {
if (user) {
setState({ ...user });
}
}, [user]);
const handleInputChange = (e) => {
let { name, value } = e.target;
setState({ ...state, [name]: value });
};
const handleSubmit = () => {
dispatch(updateUser(state, id));
history.push("/");
setError("");
};
return (
<div>
<Button
style={{ width: "100px", marginTop: "20px" }}
variant="contained"
color="secondary"
type="button"
onClick={() => history.push("/")}
>
Go Back
</Button>
<h2>Edit User</h2>
{error && <h3 style={{ color: "red" }}>{error}</h3>}
<form onSubmit={handleSubmit}>
<TextField
id="standard-basic"
label="Name"
value={name || ""}
name="name"
type="text"
required
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
name="birthday"
value={birthday || ""}
type="date"
required
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
label="img"
value={img || ""}
name="img"
type="url"
required
onChange={handleInputChange}
/>
<select
id="standard-basic"
label="status"
value={status || ""}
name="status"
onChange={handleInputChange}
>
<option value={""}>Brak informacji</option>
<option value={"Alive"}>Alive</option>
<option value={"Dead"}>Dead</option>
</select>
<Button
style={{ width: "100px" }}
variant="contained"
color="primary"
type="submit"
onChange={handleInputChange}
>
Update
</Button>
</form>
</div>
);
};
EDIT ADDED REDUCER
const fetchState = {
users: [],
user: {},
};
export const userReducer = (state = fetchState, { type, payload }) => {
switch (type) {
case USERS_FETCH:
return { ...state, users: payload };
case ADD_USER:
return { ...state, users: [...state.users, payload] };
case UPDATE_USER:
return { ...state, users: [...state.users, payload] };
case GET_SINGLE_USER:
return {
...state,
user: payload,
};
default:
return state;
}
};
export const selectedUserReducer = (state = {}, { type, payload }) => {
switch (type) {
case GET_USER:
return { ...state, ...payload };
default:
return state;
}
};
There might be another way to achieve the same result. I am posting mine.
You can alter your object in the reducer and store only the data which you want to.
eg:-
case UPDATE_USER: {
const updateState = {
...state.user.appearance,
name: payload.name,
birthday: payload.birthday,
img: payload.img,
status: payload.status,
id: payload.id
};
return {
...state,
updateState,
};
}
USER REDUCER
const fetchState = {
user: [
name: "",
birthday: "",
img: "",
status: "",
appereance: "",
]
}
Please try and let me know , cheers !

React TypeScript: Multiple State updates but only first one gets applied

I made a sandBox here https://codesandbox.io/s/old-mountain-xl7nz when you don't full in any of the form inputs I expect to see 3 errors but I only get one. I don't understand why
import React, { ChangeEvent, useState } from 'react';
import { Link } from 'react-router-dom';
import loadingImg from '../images/loading.svg';
const Join: React.FC = () => {
const [state, setState] = useState({
email: '',
emailError: '',
fullName: '',
fullNameError: '',
loading: false,
password: '',
passwordError: '',
});
const {
email,
emailError,
fullName,
fullNameError,
password,
passwordError,
} = state;
const onChange = (event: ChangeEvent<HTMLInputElement>) => {
event.persist();
setState((prev) => ({
...prev,
[event.target.id]: event.target.value,
}));
};
const onSubmit = (event: React.FormEvent) => {
event.preventDefault();
if (validate('fullName') && validate('email') && validate('password')) {
console.log('FIRE FORM');
}
};
const onBlur = (event: ChangeEvent<HTMLInputElement>) => {
validate(event.target.id);
};
const validate = (id: string) => {
switch (id) {
case 'fullName':
if (!/^.{6,7}$/.test(fullName)) {
setState((prev) => ({ ...prev, fullNameError: 'err' }));
return false;
} else {
setState((prev) => ({ ...prev, fullNameError: '' }));
return true;
}
break;
case 'email':
if (!/\S+#\S+\.\S+/.test(email)) {
setState((prev) => ({ ...prev, emailError: 'err' }));
return false;
} else {
setState((prev) => ({ ...prev, emailError: '' }));
return true;
}
break;
default:
if (!/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/.test(password)) {
setState((prev) => ({ ...prev, passwordError: 'err' }));
return false;
} else {
setState((prev) => ({ ...prev, passwordError: '' }));
return true;
}
}
};
return (
<div className='join'>
<h2>JOIN</h2>
<h3>some subheading</h3>
<form onSubmit={onSubmit}>
<label>Name</label>
<input
type='text'
placeholder='Full name'
id='fullName'
value={fullName}
onChange={onChange}
onBlur={onBlur}
/>
{fullNameError}
<label>Email</label>
<input
type='text'
placeholder='Email address'
id='email'
value={email}
onChange={onChange}
onBlur={onBlur}
/>
{emailError}
<label>Password</label>
<input
type='password'
placeholder='Create a password'
id='password'
value={password}
onChange={onChange}
onBlur={onBlur}
/>
{passwordError}
<button color='primary'>
{!state.loading ? (
'Join Now'
) : (
<img src={loadingImg} alt='loadingd' className='loading' />
)}
</button>
<div className='join--terms'>
By joining, you agree to our
<Link to={{ pathname: '/terms' }}> Terms of Service</Link> and
<Link to={{ pathname: '/terms' }}> Privacy Policy</Link>
</div>
</form>
</div>
);
};
export { Join };
your conditions are not evaluating when first condition is false...
so you better to do something like this....
const onSubmit = (event: React.FormEvent) => {
event.preventDefault();
const fullNameValidation = validate('fullName')
const emailValidation = validate('email')
const passwordValidation = validate('password')
if (fullNameValidation && emailValidation && passwordValidation) {
console.log('FIRE FORM');
}
};

Resources