0

In my react/redux app whenever i pass the form data to POST api i get an error

Unhandled Rejection (TypeError): Cannot read property 'data' of undefined/

The data is still being submitted to the Django back-end since when i check data in my back-end, I can confirm the data i did input in the form was submitted and saved. However it's the front-end that i think has the error. What i'm i missing?

Form component

class FormInvoice extends Component {
  state = {
    invoiceOwner: "",
    product: "",
    quantity: "",
    mode: "",
    status: "",
    payment_made: "",
  };

  static propTypes = {
    addInvoiceData: PropTypes.func.isRequired,
  };

  onChange = (e) =>
    this.setState({
      [e.target.name]: e.target.value,
    });

  onSubmit = (e) => {
    e.preventDefault();
    const {
      invoiceOwner,
      product,
      quantity,
      mode,
      status,
      payment_made,
    } = this.state;
    const invoice = {
      invoiceOwner,
      product,
      quantity,
      mode,
      status,
      payment_made,
    };
    this.props.addInvoiceData(invoice); <=== Action for passing data to POST api
  };
  render() {
    const {
      invoiceOwner,
      product,
      quantity,
      mode,
      status,
      payment_made,
    } = this.state;
    return (
      <div className="App container">
        <Modal isOpen={this.props.newInvoiceModal} scrollable={true}>
          <ModalHeader toggle={this.props.toggleModal}>Add Invoice</ModalHeader>
          <ModalBody>
            <FormGroup>
              <Label for="title">Name</Label>
              <Input
                name="invoiceOwner"
                value={invoiceOwner}
                onChange={this.onChange}
              />
            </FormGroup>
            <FormGroup>
              <Label for="title">Product</Label>
              <Input name="product" value={product} onChange={this.onChange} />
            </FormGroup>

            <FormGroup>
              <Label for="title">Quantity</Label>
              <Input
                name="quantity"
                value={quantity}
                onChange={this.onChange}
              />
            </FormGroup>
            <FormGroup>
              <Label for="title">Mode</Label>
              <Input name="mode" value={mode} onChange={this.onChange} />
            </FormGroup>
            <FormGroup>
              <Label for="title">Status</Label>
              <Input name="status" value={status} onChange={this.onChange} />
            </FormGroup>
            <FormGroup>
              <Label for="title">Paid</Label>
              <Input
                name="payment_made"
                value={payment_made}
                onChange={this.onChange}
              />
            </FormGroup>
          </ModalBody>
          <ModalFooter>
            <button onClick={this.onSubmit} className="btn btn-primary">
              Submit
            </button>{" "}
            <Button color="secondary" onClick={this.props.toggleModal}>
              Cancel
            </Button>
          </ModalFooter>
        </Modal>
      </div>
    );
  }
}

export default connect(null, { addInvoiceData })(FormInvoice);

Redux part

// API
const api = Axios.create({
  baseURL: "http://localhost:8000/api",
  timeout: 30000,
  headers: {
    "Content-Type": "application/json",
    "Accept": "application/json",
  },
});

api.interceptors.request.use(
  (config) => {
    if (localStorage.getItem("access")) {
      config.headers.Authorization = `JWT ${localStorage.getItem("access")}`;
    }

    return config;
  },
  (error) => Promise.reject(error)
);
export default api;

// ADD INVOICE DATA
import API from "../api"

export const addInvoiceData = (invoice) => async (dispatch) => {
  await API.post("/clients/invoice/", invoice)
    .then((res) => {
      dispatch(createMessage({ addInvoiceData: "Invoice detail added" }));
      dispatch({
        type: ADD_INVOICE_DATA,
        payload: res.data,
      });
      dispatch({
        type: TOGGLE_MODAL,
      });
    })
    .catch((err) =>
      dispatch(returnErrors(err.response.data, err.response.status))
    );
};

//Reducer
const initialState = {
  invoiceData: [],
  newInvoiceModal: false,
};

export default function (state = initialState, action) {
  switch (action.type) {
    case GET_INVOICE_DATA:
      return {
        ...state,
        invoiceData: action.payload,
      };

    case ADD_INVOICE_DATA:
      return {
        ...state,
        invoiceData: action.payload,
      };
  }
}
7
  • Does API.post return anything? It would return a promise or the API.post("/clients/invoice/", invoice).then would cause an error but does the promise resolve to anything? Commented Aug 7, 2020 at 9:37
  • API is not the same as api, JavaScript is case sensitive. Did you export api and import it as API? What is the API.post function? Commented Aug 7, 2020 at 9:52
  • Then I guess the request fails and err.response.data causes the error, can you see the request in the network tab and see if it fails with data? Commented Aug 7, 2020 at 9:54
  • ADD_INVOICE_DATA gets dispatched and the state is updated. So err.response.data is not triggered. Commented Aug 7, 2020 at 9:56
  • The only 2 places where the error Cannot read property 'data' of undefined/ can occur in the code posted is in payload: res.data, or err.response.data maybe you can post the code where the error occurs? Commented Aug 7, 2020 at 10:02

1 Answer 1

3

The problem is on here:

    .then((res) => {
      dispatch(createMessage({ addInvoiceData: "Invoice detail added" }));
      ...
    })
    .catch((err) =>
      // not every err looks like : err.response.data
      dispatch(returnErrors(err.response.data, err.response.status))
    );

If any exception accours in the first block, the catch tries to handle it and it calls err.response.data . and since err.response is undefined, you get Cannot read property 'data' of undefined error.

So add a try catch statement in your first block to catch the exceptions on first block currectly:

.then((res) => {
  try{
    dispatch(createMessage({ addInvoiceData: "Invoice detail added" }));
    ...
  }
  catch(e) {
    console.log(res, e)
  }
}).catch((err) =>
  dispatch(returnErrors(err.response.data, err.response.status))
);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.