'In React-Redux,how do i get the status of a saga function call in reactjs component?

I am new to reactjs and react-redux. I've joined a project that's building a project from a reactjs with react-redux template. I have two tables through axios - places(id,city,state,country) and resorts(resortId,name,address,phone,details and placeId).Through axios api in redux, the api -api/resorts return these data -(resortId,name,address,phone,details,placeId,city,state,country) to be bound to my grid.

The grid has a modal dialog for add/edit in which it has city,state,country dropdowns. So, the city Id is the placeId foreign key in the resorts table which I'm sending back on the apis for add and edit. I'm also sending extra data on add/edit of resorts - city,state and country(though these 3 belong to place table) to the add/edit apis because the grid is bound from ComponentDidUpdate function where resorts is assigned this.props. But after the resort is successfully added or updated into the resort table,in the ComponentDidUpdate table in the this.props - the grid data for only resort being updated or added has these 3 missing - state,city and country but all the other resort data in this.props has all these state,city and country intact. This is happening despite the fact that i'm sending these 3 city,state and country(doesn't belong to resort table) in resort entity that's being sent to the add or edit apis. Do I call getResorts saga again or add these missing 3 in this.props after finding the resort by Id in componentDidUpdate?

ComponentDidUpdate is

      componentDidUpdate(prevProps, prevState, snapshot) {
    ///I need to get the status from saga for add or edit successs here
    /// and either call the getresorts all function again or add the missing 3 city,state and country 
    //this.props before its being assigned to { resorts } for the particatular resortId being added or edited
    console.log(data);
    const { resorts } = this.props;

    if (!isEmpty(resorts) && size(prevProps.resorts) !== size(resorts)) {

    this.setState({ resorts: {}, isEdit: false });
    }
    }

The code is as below

1)resort-list.js

            import React, { Component} from "react";
        import PropTypes, { number } from "prop-types";
        import { connect } from "react-redux";
        import MetaTags from "react-meta-tags";
        import { withRouter, Link } from "react-router-dom";
        import {
        Card,
        CardBody,
        Col,
        Container,
        Row,
        Modal,
        Button,
        ModalHeader,
        ModalBody,
        Label
        } from "reactstrap";
        import paginationFactory, {
        PaginationProvider,
        PaginationListStandalone,
        } from "react-bootstrap-table2-paginator";
        import ToolkitProvider, { Search } from "react-bootstrap-table2-toolkit";
        import BootstrapTable from "react-bootstrap-table-next";
        import images from "assets/images";
        import { Formik, Field, Form, ErrorMessage } from "formik";
        import * as Yup from "yup";
        //Import Breadcrumb
        import Breadcrumbs from "components/Common/Breadcrumb";
        import DeleteModal from "components/Common/DeleteModal";
        import resortsSaga from 'store/resorts/saga';
        import { select } from 'redux-saga/effects';
        import {
        getResorts,
        addNewResort,
        updateResort,
        deleteResort,
        } from "store/resorts/actions";

        import store from 'store/index';
        import {
        getPlaces,
        getPlaceDetails
        } from "store/places/actions";

        import { isEmpty, size, map } from "lodash";
        import { getFormInitialValues } from "redux-form";
        class ResortsList extends Component {
        constructor(props) {
        super(props);
        this.node = React.createRef();
        this.state = {
        placeId:number,
        resorts: [],
        places:[],
        previousPlace: {},
        resort: "",
        modal: false,
        deleteModal: false,
        resortsListColumns: [
        {
        text: "#ID",
        dataField: "id",
        sort: true,
        hidden: true,
        formatter: (cellContent, resort) => <>{resort.id}</>,
        },
        {
        dataField: "name",
        text: "Resort",
        sort: true,
        formatter: (cellContent, resort) => (
        <>
        <h5 className="font-size-14 mb-1">
        <Link to="#" className="text-dark">
        {resort.name}
        </Link>
        </h5>
        <p className="text-muted mb-0">{resort.name}</p>
        </>
        ),
        },
        {
        dataField: "address",
        text: "Address",
        sort: true,
        },
        {
        dataField: "phone",
        text: "Phone",
        sort: true,
        },
        {
        dataField: "details",
        text: "Details",
        sort: true,
        },
        {
        dataField: "city",
        text: "City",
        sort: true,
        formatter: (cellContent, resort) => (
        <>
        <h5 className="font-size-14 mb-1">
        <Link to="#" className="text-dark">
        {resort.city}
        </Link>
        </h5>
        <p className="text-muted mb-0">{resort.city}</p>
        </>
        ),

        },

        {
        dataField: "state",
        text: "State",
        sort: true,
        },
        {
        dataField: "country",
        text: "Country",
        sort: true,
        },
        {
        dataField: "menu",
        isDummyField: true,
        editable: false,
        text: "Action",
        formatter: (cellContent, resort) => (
        <div className="d-flex gap-3">
        <Link
        to={"/resort-detail/" + resort}
        >

        <i
        className="mdi mdi-eye font-size-18"
        id="resortdetails"

        ></i>
        </Link>
        <Link className="text-success" to="#">
        <i
        className="mdi mdi-pencil font-size-18"
        id="edittooltip"
        onClick={() => this.handleResortClick(resort)}
        ></i>
        </Link>
        <Link className="text-danger" to="#">
        <i
        className="mdi mdi-delete font-size-18"
        id="deletetooltip"
        onClick={() => this.onClickDelete(resort)}
        ></i>
       </Link>
        </div>
        ),
        },
        ],
        };
        this.handleResortClick = this.handleResortClick.bind(this);
        this.toggle = this.toggle.bind(this);
        this.handleResortClicks = this.handleResortClicks.bind(this);
        this.onClickDelete = this.onClickDelete.bind(this);
        }

        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 });
        }

        toggle() {
        this.setState(prevState => ({
        modal: !prevState.modal,
        }));
        }


        handleResortClicks = () => {
        this.setState({ resort: "", isEdit: false });
        this.toggle();
        };

        componentDidUpdate(prevProps, prevState, snapshot) {
        let data = yield select(getResortsSuccess);
        console.log(data);
        const { resorts } = this.props;

        if (!isEmpty(resorts) && size(prevProps.resorts) !== size(resorts)) {

        this.setState({ resorts: {}, isEdit: false });
        }
        }

        onPaginationPageChange = page => {
        if (
        this.node &&
        this.node.current &&
        this.node.current.props &&
        this.node.current.props.pagination &&
        this.node.current.props.pagination.options
        ) {
        this.node.current.props.pagination.options.onPageChange(page);
        }
        };

        /* Insert,Update Delete data */
        toggleDeleteModal = () => {
        this.setState(prevState => ({
        deleteModal: !prevState.deleteModal,
        }));
        };

        onClickDelete = (resorts) => {
        this.setState({ resorts: resorts });
        this.setState({ deleteModal: true });
        };

        handleDeleteResort = () => {
        const { onDeleteResort } = this.props;
        const { resorts } = this.state;
        if (resorts.id !== undefined) {
        onDeleteResort(resorts);
        this.setState({ deleteModal: false });
        }
        };

        handleResortClick = arg => {
        const resort = arg;

        this.setState({
        resort: {
        id: resort.id,
        name: resort.name,
        address: resort.address,
        phone:resort.phone,
        details: resort.details,
        placeId:resort.placeId,
        city:resort.city,
        state: resort.state,
        country: resort.country,
        },
        isEdit: true,
        });
        this.toggle();
        };

        render() {
        const { SearchBar } = Search;
        const { resorts } = this.props;
        const { places } = this.props;
        const { isEdit,deleteModal} = this.state;
        const { onAddNewResort, onUpdateResort } = this.props;
        const { selectedResort } = this.state;
        const resort= this.state.resort;

        // console.log(resort);
        const pageOptions = {
        sizePerPage: 10,
        totalSize: resorts.length, // replace later with size(users),
        custom: true,
        };
        const selectRow = {
        mode: "checkbox",
        };

        return (
        <React.Fragment>
        <DeleteModal
        show={deleteModal}
        onDeleteClick={this.handleDeleteResort}
        onCloseClick={() => this.setState({ deleteModal: false })}
        />
        <div className="page-content">
        <MetaTags>
        <title>Resort List | Wedding Destination Admin & Dashboard</title>
        </MetaTags>
        <Container fluid>
        {/* Render Breadcrumbs */}
        <Breadcrumbs title="Resorts" breadcrumbItem="Resorts List" />
        <Row>
        <Col lg="12">
        <Card>
        <CardBody>
        <PaginationProvider
        pagination={paginationFactory(pageOptions)}
        keyField="id"
        columns={this.state.resortsListColumns}
        data={resorts}
        >
        {({ paginationProps, paginationTableProps }) => (
        <ToolkitProvider
        keyField="id"
        columns={this.state.resortsListColumns}
        data={resorts}
        search
        >
        {toolkitprops => (
        <React.Fragment>
        <Row className="mb-2">
        <Col sm="4">
        <div className="search-box ms-2 mb-2 d-inline-block">
        <div className="position-relative">
        <SearchBar
        {...toolkitprops.searchProps}
        />
        <i className="bx bx-search-alt search-icon" />
        </div>
        </div>
        </Col>
        <Col sm="8">
        <div className="text-sm-end">
        <Button
        color="primary"
        className="font-16 btn-block btn btn-primary"
        onClick={this.handleResortClicks}
        >
        <i className="mdi mdi-plus-circle-outline me-1" />
        Create New Resort
        </Button>
        </div>
        </Col>
        </Row>
        <Row>
        <Col xl="12">
        <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"
            ),

            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,
            };
            // 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"],
            };
            // 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>
        </Col>
        </Row>
        <Row className="align-items-md-center mt-30">
        <Col className="pagination pagination-rounded justify-content-end mb-2">
        <PaginationListStandalone
        {...paginationProps}
        />
        </Col>
        </Row>
        </React.Fragment>
        )}
        </ToolkitProvider>
        )}
        </PaginationProvider>
        </CardBody>
        </Card>
        </Col>
        </Row>
        </Container>
        </div>
        </React.Fragment>
        );
        }
        }

        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)),
        });
        export default connect(
        mapStateToProps,
        mapDispatchToProps
        )(withRouter(ResortsList));
  1. resort(in redux store) - saga.js

        import { call, put, takeEvery } from "redux-saga/effects"
    
    // Crypto Redux States
    import {
    GET_RESORTS,
    GET_RESORT_DETAILS,
    ADD_NEW_RESORT,
    DELETE_RESORT,
    UPDATE_RESORT
    } from "./actionTypes"
    
    import {
    addResortFail,
    addResortSuccess,
    updateResortSuccess,
    updateResortFail,
    deleteResortSuccess,
    deleteResortFail,
    } from "./actions"
    
    //Include Both Helper File with needed methods
    import {
    addNewResort,
    updateResort,
    deleteResort
    } from "../../helpers/fakebackend_helper"
    
    
    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* 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* 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
    
  2. resort(in redux store) - action.js

                 import {
                 ADD_NEW_RESORT,
                 ADD_RESORT_SUCCESS,
                 ADD_RESORT_FAIL,
                 UPDATE_RESORT,
                 UPDATE_RESORT_SUCCESS,
                 UPDATE_RESORT_FAIL,
             } from "./actionTypes"
    
             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,
             })
    


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source