Unable to set props values after delete the record from the list in React context API

Viewed 754

We're working with the project, in which we're having different roles as business, users, organization. For that, we're having different tabs for roles.

While clicking on each tab we want to bind the list of organizations, currently we were repeating the code of getting list of organizations on each file, which is not best practices thus, we have used context API, which will make it more robust, to use a single file of code to get a list of organizations.

Everything works fine, however, after deleting organization from the list, I'm unable to set props. Here is the code:

context.js

import React from 'react';
export const {Provider, Consumer} = React.createContext({})

List.js

import React, { Component } from "react";
import { Consumer } from '../../components/context';

export default  class List extends Component {
  state = {
    organizations: [],
  };

  deleteOrganization(id) {
    var self = this;
    OrganizationService.deleteOrganization(id)
      .then(function(response) {
        if (response.status === 200) {
          self.handleDeleteSuccessResponse(response);
        } else {
          console.log(response.data.errors)
        }
      })
      .catch(function(error) {
        console.log(error.response.data.errors)
      });
  }

  handleDeleteSuccessResponse(response) {
    var self = this;
    const organizations = self.state.organizations.filter(
      organization => organization.id !== self.state.alert.objectId
      );
      if (organizations.length === 0) {
        this.getOrganizations();
      }
        this.props.context.updateValue(organizations); //seems like props not getting here
        self.setState({
      organizations: organizations
    });
  }

  render() {
    const { organizations} = this.state;
    const { match } = this.props;
    return (
      <div className="welcome-wrap">
        <h3 className="text-center">Organizations</h3>
        <hr />

        <Consumer>
          {(context) => (
            <Component
              { ...this.props }
              context={context}
            />,
             console.log(context),
            <table className="table table-bordered">
              <thead>
                <tr>
                  <th scope="col">Name</th>
                </tr>
              </thead>
              <tbody>
                {context.value.organizations.map(organization => (
                  <tr key={organization.id}>
                    <td>{organization.name}</td>
                     <td>
                      <a
                        className="delete-btn"
                        onClick={event => this.deleteOrganization(organization.id)}
                      >
                        Delete
                      </a>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
            )
          }
        </Consumer>
      </div>
    );
  }
}

User.js

import React, { Component } from "react";
import { Provider } from './../context';

// Import helper
import {
  currentLoggedInUser,
} from "../../components/Helper";

// import service
import { OrganizationService } from "../../services/Index";

export default class User extends Component {
  constructor() {
    super()
    this.state = {
    actions: {
      getOrganizations: this.getOrganizations,
      updateValue: this.updateValue
      },
    organizations: []
    };
  };
  componentWillMount(){
    var id = currentLoggedInUser().belongs.id;
    this.getOrganizations(id);
  }
  getOrganizations(id) {
    var self = this;
    OrganizationService.getOrganizations(id)
      .then(function(response) {
        var data = response.data;
        self.setState({ organizations: data.data });
      })
      .catch(function(error) {
        console.log(error.response);
      });
  }
  updateValue = (val) => {
    this.setState({organizations: val});
  }
  render() {
        const { match } = this.props;
        return (
          <Provider value={{ value: this.state, updateValue: this.updateValue}} >
            <List />
        </Provider>
        );
      }
    }

I have created the context and define <Provider> in user.js and access <Consumer> in list.js which display all organizations.

Now I deleted some organization and it's getting deleted from the DB, however, the list is not getting the update, and I'm able to see the old values, once I refresh the page that deleted record disappears.

Now I want to send updated organizations in context but not getting props.

this.props.context.updateValue(organizations);

How can I set props for getting context?

I'm facing to update from Consumer to Provider state.

2 Answers

consider the change in the call to deleteOrganization function, your values or functions passed as context value will only be available in the render prop given to consumer, so you need to pass that function as callback to your deleteOrganization function and pass that function along with next function until you call it. instead of calling this.props.context.updateValue, the passed argument function is called.

import React, { Component } from "react";
import { Consumer } from '../../components/context';

export default  class List extends Component {
 state = {
   organizations: [],
 };

deleteOrganization(id, updateValueFn) {
  var self = this;
  OrganizationService.deleteOrganization(id)
  .then(function(response) {
    if (response.status === 200) {
       self.handleDeleteSuccessResponse(response, updateValueFn);
    } else {
      console.log(response.data.errors)
    }
  })
  .catch(function(error) {
    console.log(error.response.data.errors)
  });
}

handleDeleteSuccessResponse(response, updateValueFn) {
var self = this;
const organizations = self.state.organizations.filter(
  organization => organization.id !== self.state.alert.objectId
  );
  if (organizations.length === 0) {
    this.getOrganizations();
  }
    updateValueFn(organizations); //seems like props not getting here
    self.setState({
  organizations: organizations
});
}

render() {
const { organizations} = this.state;
const { match } = this.props;
return (
  <div className="welcome-wrap">
    <h3 className="text-center">Organizations</h3>
    <hr />

    <Consumer>
      {(context) => (
        <Component
          { ...this.props }
          context={context}
        />,
         console.log(context),
        <table className="table table-bordered">
          <thead>
            <tr>
              <th scope="col">Name</th>
            </tr>
          </thead>
          <tbody>
            {context.value.organizations.map(organization => (
              <tr key={organization.id}>
                <td>{organization.name}</td>
                 <td>
                  <a
                    className="delete-btn"
                    onClick={event => this.deleteOrganization(organization.id, context.updateValue)}
                  >
                    Delete
                  </a>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
        )
      }
    </Consumer>
  </div>
);
}
}

You can call the function passed as props in provider i.e. updateValue in the consumer just as you used consumer.value you can also call consumer.updateValue(updatedValue) which will execute the updateValue in the provider

<Consumer>
 {(context) => (
    <Component
    { ...this.props }
    context={context}
    updateValue={consumer.updateValue} // e.g. passed as prop to other component which will execute this function.
        />,
    .........
    .........

    {consumer.updateValue(someUpdatedValue)} // e.g. values can be updated by executing the function  
    .........
    .........

  }
    </Consumer>
Related