Devendra Verma
Devendra Verma

Reputation: 1015

How to pass functions to render function of React

I am not sure how to frame this question properly but I will try my best to help you understand my problem. I am little bit new to frontend so facing some difficulties. There is a controller called TableViewCotroller which is written in typescript and also includes JSX code. This controller is responsible for performing any table related operations. This controller looks like this:

import * as React from 'react';

export class TableViewController extends BaseViewController {
  constructor(props: any) {
    super(props);
  }
protected onInsertRow = async (arg: InsertArgument) => {
    //some row insertion logic
  };

protected onDeleteRow = async (arg: InsertArgument) => {
    //some row deletion logic
  };

protected onInsertColumn = async (arg: InsertArgument) => {
    //some column insertion logic
  };

protected onDeleteColumn = async (arg: InsertArgument) => {
    //some Column deletion logic
  };

render()
{
 const {//some properties} = this.props
 const {//state1, state2 etc} = this.state
 return (
  <Table
  onInsertRow={this.onInsertRow}
  onDeleteRow={this.onDeleteRow}
  onInsertColumn={this.onInsertColumn}
  onDeleteColumn={this.onDeleteColumn}
  ...//some other properties like this
 />
 );
}

Now I have decided to decouple some of these commands like onInsertRow, onInsertColumn etc from TableViewController and move them to TableCommandingController. My TableCommandingController looks like this :

export class TableCommanding implements ITableCommandingController{
constructor(props: any) {
    super(props);
  }
    protected onDeleteRow = async (arg: InsertArgument) => {
        //some row deletion logic
      };
    
    protected onInsertColumn = async (arg: InsertArgument) => {
        //some column insertion logic
      };
    
    protected onDeleteColumn = async (arg: InsertArgument) => {
        //some Column deletion logic
      };
    
   //Some other commands
}

After creating TableCommandingController, I have added a variable in TableViewController called tableCommandingController. Something like below:

export class TableViewController extends BaseViewController {

private tableCommandingController?: TableCommandingController;
  constructor(props: any) {
    super(props);
  }

//Rest of the class
}

Now I will initialize this tableCommandingController in async fashion. I don't want to initialize it in synchronous manner(there is some other requirement). So I created a function and I will initialize it in there. Now my TableViewController looks like this:

export class TableViewController extends BaseViewController {

    private tableCommandingController?: TableCommandingController;

    constructor(props: any) {
        super(props);
    }

    protected getCommandingController = async () => {
        if (this.tableCommandingController !== undefined) return this.tableCommandingController;

        //Here I will lazy load TableCommandingModule using webpack magic comment
       const {TableCommanding } = await import(/* webpackChunkName: "TableCommandingController" */ './TableCommandingController');
       this.tableCommandingController = new TableCommanding(this.props);
       return this.tableCommandingController;
    }
}

Now when I have tableCommanding initialized, I wanted to use tableCommanding's onInsertRow, onInsertColumn etc functions inside render of TableViewController. But I have no idea how can I do that. I have tried something below but it was not working:

render()
    {
     const {//some properties} = this.props
     const {//state1, state2 etc} = this.state
     return (
      <Table
      onInsertRow={this.tableCommandingController?.onInsertRow}
      onDeleteRow={this.tableCommandingController?.onDeleteRow}
      onInsertColumn={this.tableCommandingController?.onInsertColumn}
      onDeleteColumn={this.tableCommandingController?.onDeleteColumn}
      ...//some other properties like this
     />
     );
    }

In the above method my tableCommandingController is always uninitialized. So I know that I need to call getCommandingController() to get the initialized value of tableCommandingController. Something like below:

async render()
    {
     const commanding = await this.getTableCommandingController();
     const {//some properties} = this.props
     const {//state1, state2 etc} = this.state
     return (
      <Table
      onInsertRow={commanding .onInsertRow}
      onDeleteRow={commanding .onDeleteRow}
      onInsertColumn={commanding .onInsertColumn}
      onDeleteColumn={commanding .onDeleteColumn}
      ...//some other properties like this
     />
     );
    }

But I cannot make render function async. Any idea how can I do this?

Upvotes: 0

Views: 553

Answers (1)

alchemist95
alchemist95

Reputation: 794

Please keep your render method only to destructure props, state, any small sync operation and returning JSX. Render methods are not meant for async operations. Async operations needs to be handled through react lifecycle methods. Read up lifecycle methods here: https://reactjs.org/docs/state-and-lifecycle.html

You should ideally do this operation in componentDidMount and use state to re-render your component so that the callbacks are re-assigned. Else, without a re-render, your JSX wouldn't have the actual callback, instead would be undefined as that's what was rendered during mount.

Upvotes: 1

Related Questions