0

I'm passing information from Component A from the Component B. After that depending on the props id I'm calling an API and setting the data to states. However, when I called the setState parameter to set the the API loaded data, the API were been called contentiously. Here's the Component B code:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import Modal from "react-bootstrap/Modal";
import PropTypes from 'prop-types'
import axios from 'axios';

import TextBox from '../../layouts/textBox'

import { getPermission } from '../../actions/permissionActions';

class Form extends Component {
 
  state = {
    editSelectedPermissions: []
  }


  async componentDidMount() {
   this.props.getPermission();
  }

  async componentDidUpdate() {
    const roleId = this.getRoleId();

    if (roleId) {
      const res = await axios.get(`http://localhost:3000/v1/permissions/role/${roleId}/`);
      console.log(res.data.data);
      if ( res.data.data.permission.length != 0) {
          this.setState({
            editSelectedPermissions: res.data.data.permission
          })
      } 
    }
  }

  getRoleId=()=> this.props.data.id

  render() {

    const { onCloseModal, onSubmit, onChange, onCheckBox, permissions } = this.props;

    const { showModal, id, name, description} = this.props.data;

   const { editSelectedPermissions } = this.state;

    let selectedPermission = false;

    return (
      <div>
        <Modal show={showModal} centered onHide={onCloseModal}>
          <Modal.Header closeButton>{id ? "Edit" : "Add"} User Role</Modal.Header>
          <Modal.Body>
            <form onSubmit={onSubmit.bind(this)}>

              <input type="hidden" name="id" value={id} />

              <div className="form-row">
                <div className="col-md-6">
                  <TextBox type="text" name="name" placeholder="Enter Name" label="Name" value={name} onChange={onChange} />
                </div>
                <div className="col-md-6">
                  <TextBox type="text" name="description" placeholder="Enter Description" label="Description" value={description} onChange={onChange} />
                </div>
              </div>
              
              {permissions.map((item, index) => {

                if (editSelectedPermissions.length > 0)
                  selectedPermission = editSelectedPermissions.find((item2) => item2.id === item.id)

                return (
                  <div className="form-check" key={index}>
                    <input className="form-check-input"  type="checkbox" name="permission" checked={selectedPermission} onChange={onCheckBox} value={item.id}/>
                    <label className="form-check-label" htmlFor="defaultCheck1">
                      {item.name}
                    </label>
                  </div>
                )
              })}

              <div className="d-flex justify-content-center">
                <input
                  type="submit"
                  className="btn btn-primary"
                  value={id ? "Edit Record" : "Create Record"}  
                />
              </div>
            </form>
          </Modal.Body>
        </Modal>
      </div>
    );
  }
}

Form.propTypes = {
  getPermission: PropTypes.func.isRequired,
}

const mapStateToProps = (state) => ({
  permissions: state.permission.permissions
});

export default connect(mapStateToProps,  {getPermission} )(Form);

Any reason why it's been called continuously?

FR STAR
  • 662
  • 4
  • 24
  • 50
  • componentDidUpdate is called after every state update. If `roleId` is truthy once, you make the request, your state changes, your component rerenders, `componentDidUpdate` is called and `roleId` is still truthy, hence you make another network request. Rinse and repeat. – hotpink Jun 28 '20 at 06:56

4 Answers4

1

componentDidUpdate run each time state or props change. Because you setState inside, after it it will run again, change state again, and run again infinitely. Add checker before setState

if ( res.data.data.permission.length != 0 && this.state.editSelectedPermisssions != res.data.data.premission) {
          this.setState({
            editSelectedPermissions: res.data.data.permission
          })
      } 
Hagai Harari
  • 2,767
  • 3
  • 11
  • 23
0

Call API in componentDidMount cycle rather than in componentDidUpdate.

Bilal
  • 25
  • 1
  • 7
  • if I called the componentDidMount I'm not getting the updated id which sent from parent component – FR STAR Jun 28 '20 at 06:58
0

It's because

if (roleId) //always true

this statement is always true.

Maybe you could store current roleId and and do the comparision

if (this.state.currentRoleId !== roleId) {
  const res = await axios.get(`http://localhost:3000/v1/permissions/role/${roleId}/`);
  console.log(res.data.data);
  if ( res.data.data.permission.length != 0) {
      this.setState({
        currentRoleId: roleId,
        editSelectedPermissions: res.data.data.permission
      })
  } 
}
 
Sabster
  • 51
  • 5
0

It is simply because your component update frequently as such it keeps making the API call and this is because you are making the API call in componentDidUpdate. Usually, you make the API call in componentDidMount, this will make the API call once.

async componentDidMount() {
      this.props.getPermission();
      const res = await axios.get(`http://localhost:3000/v1/permissions/role/${roleId}/`); // should be make here
  }

Not in

componentDidUpdate(){
  //Avoid Making API calls here
}
Friday Ameh
  • 1,664
  • 1
  • 10
  • 15