2

I know how to handle this inside a function, but in my case none of those solutions works and I still get

this is undefined

The problem is I have a function inside render() method and I dont know how to handle it.

This is a part of my code

class Pagination extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
         //states
    }
    this.changePage = this.changePage.bind(this);
  }

changePage (event) {
   // some codes
}

 render() {
     function PrevPage() {
      return (
        <li key="p-page" onClick={this.changePage}>
          <a href="#">&lt;</a>
        </li>
      )
     }
    return (
         <div>
           <PrevPage />
            ...
         </div>
     )
 }
}

I get the error at this line

<li key="n-page" onClick={this.changePage}>

I tried putting this line in constructor:

 this.PrevPage= this.PrevPage.bind(this);

but PrevPage is not recognized by this.

Also if i convert PervPage to arrow function:

PrevPage = () => {
  return (
    <li key="p-page" onClick={this.changePage}>
      <a href="#">&lt;</a>
    </li>
  )
}

I get this error:

'PrevPage' is not defined no-undef

I know I'm missing somthing but I cant figure out what

Ghasem
  • 14,455
  • 21
  • 138
  • 171
  • the problem with using is that it is not a react component. it's a simple function local to render hence use JSX Expression {PrevPage()} and it will return you the JSX you have returned. – its4zahoor Aug 27 '19 at 07:20
  • 1
    *"'PrevPage' is not defined no-undef"* You have to use `const`, `let` or `var` when you declare a variable. Then it will work. – Felix Kling Aug 27 '19 at 07:24
  • @FelixKling You're right. I wouldv'e fix the issue before I ask the question If I haven't missed a 'const' before the arrow function. But asking this question and looking at the answer taught me new things! – Ghasem Aug 27 '19 at 09:18

8 Answers8

2

Why not just remove the function outside the render? Generally speaking you want to keep the render logic as clean as possible and your PrevPage component can really just be a normal method. Seems kind of superfluous to define a child-component within render, and then return it immediately.

class Pagination extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
         //states
    }
    this.changePage = this.changePage.bind(this);
    this.prevPage = this.prevPage.bind(this);
  }

changePage (event) {
   // some codes
}

prevPage() {
   return (
     <li key="p-page" onClick={this.changePage}>
        <a href="#">&lt;</a>
     </li>
   )
}

 render() {
    return (
         <div>
            {this.prevPage()}
            ...
         </div>
     )
 }
}

Or if you want, just create a brand-new component for PrevPage, and pass down the changePage handler as props. The changeHandler will still be bound to the Pagination component context.

PrevPage.js

const PrevPage = (props) => {
   return (
     <li key="p-page" onClick={props.changePage}>
        <a href="#">&lt;</a>
     </li>
   )
}

export default PrevPage

Pagination.js

class Pagination extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
         //states
    }
    this.changePage = this.changePage.bind(this);
  }

changePage (event) {
   // some codes
}

 render() {
    return (
         <div>
            <PrevPage changePage={this.changePage}/>
         </div>
     )
 }
}
Chris Ngo
  • 15,460
  • 3
  • 23
  • 46
  • 1
    There are many great solutions for my answer here. I just tried yours and it worked. Thanks to you and everyone else. Also I wanted to do it before I ask, but I didn't know how to call it in render. – Ghasem Aug 27 '19 at 07:27
  • 1
    Definitely, this was very well-received question. :). Thanks for accepting mine and thanks for asking! I also learned something from this experience! – Chris Ngo Aug 27 '19 at 07:28
0

You have multiple options:

  1. bind PrevPage inside render:

    render() {
         function PrevPage() {
          return (
            <li key="p-page" onClick={this.changePage}>
              <a href="#">&lt;</a>
            </li>
          )
         }
         PrevPage = PrevPage.bind(this);
        return (
             <div>
               <PrevPage />
                ...
             </div>
         )
     }
    }
    
  2. Save this in a different variable:

    render() {
        const that = this;
         function PrevPage() {
          return (
            <li key="p-page" onClick={that.changePage}>
              <a href="#">&lt;</a>
            </li>
          )
         }
        return (
             <div>
               <PrevPage />
                ...
             </div>
         )
     }
    }
    
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
0

You have to bind you function to contructor and call the function on your li tag as an arrow function and also put your PrevPage function outside render function like this:

class Pagination extends React.Component {


constructor(props) {
    super(props);
    this.state = {
         //states
    }
    this.changePage = this.changePage.bind(this);
    this.PrevPage = this.PrevPage.bind(this);
  }

changePage (event) {
// some codes
}

PrevPage() {
    return (
        <li key="p-page" onClick={this.changePage}>
        <a href="#">&lt;</a>
        </li>
    )
}

render() {

    return (
        <div>
        { this.PrevPage() }
            ...
        </div>
    )
}

}

Hope it helps

M. Xhafa
  • 79
  • 1
  • 6
0

Your PrevPage should be a separate component. It is not a good pattern to define a new component in the render function.

You can define it as a function component:

const PrevPage => (props) {
    return (
        <li key="p-page" onClick={props.onChangePage}>
            <a href="#">&lt;</a>
        </li>
    )
}

class Pagination extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            //states
        }
        this.changePage = this.changePage.bind(this);
    }

    changePage (event) {
        // some codes
    }

    render() {
        return (
            <div>
                <PrevPage onChangePage={this.changePage}/>
                ...
            </div>
        )
    }
}

Denys Kozak
  • 487
  • 1
  • 4
  • 13
0

What you've defined is a private function inside render method, therefore your attempt to bind it in the constructor not works, you have 2 choices:

  1. Convert PrevPage function to arrow-function.
class Pagination extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      //states
    };
    this.changePage = this.changePage.bind(this);
  }

  changePage(event) {
    // some codes
  }

  render() {
    const PrevPage = () => {
      return (
        <li key="p-page" onClick={this.changePage}>
          <a href="#">&lt;</a>
        </li>
      );
    };

    return (
      <div>
        <PrevPage />
        ...
      </div>
    );
  }
}

  1. Make PrevPage function as a class method, and then bind it in the constructor as you did - this method will preform better, cause you won't make a closure each time render method is called.
class Pagination extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      //states
    };
    this.changePage = this.changePage.bind(this);
    this.renderPrevPage = this.renderPrevPage.bind(this);
  }

  changePage(event) {
    // some codes
  }

  render() {
    return (
      <div>
        {this.renderPrevPage()}
        ...
      </div>
    );
  }

  renderPrevPage() {
    return (
      <li key="p-page" onClick={this.changePage}>
        <a href="#">&lt;</a>
      </li>
    );
  }
}

felixmosh
  • 32,615
  • 9
  • 69
  • 88
0

There are 2 issues in your code.

  1. You are creating a function PrevPage in render method and calling it as a component instead you have to call it as a function.

  2. You are not binding the method changePage correctly to OnClick.

    This is how I will write this code.

    render() {
     function PrevPage() {
      return (
        <li key="p-page" onClick={ () => this.changePage }>
          <a href="#">&lt;</a>
        </li>
      )
     }
    return (
         <div>
           {PrevPage()}
            ...
         </div>
     )
    

I will suggest you to write PrevPage function outside the render method and call it like this.

{this.PrevPage}

Hope it helps you.

Abhishek Gautam
  • 333
  • 2
  • 11
  • *"You are creating a function PrevPage in render method and calling it as a component instead you have to call it as a function. "* That's not true. Components can be classes or functions. – Felix Kling Aug 27 '19 at 07:25
  • if defined outside render then `{this.PrevPage()}`, use `()` since you want it to run imediately and return jsx, otherwise it will not run and no jsx returned. – its4zahoor Aug 27 '19 at 07:26
  • *"You are not binding the method changePage correctly to OnClick."* The OP does is right. It's incorrect in your code. It should be `onclick={(e) => this.changePage(e)}` which is exactly the same as `onclick={this.changePage}`. In other words, the two issues you are pointing out are not issues at all. – Felix Kling Aug 27 '19 at 07:28
-1

try

<li key="n-page" onClick={() => this.changePage()}>
Ghasem
  • 14,455
  • 21
  • 138
  • 171
Jonathan Irwin
  • 5,009
  • 2
  • 29
  • 48
  • Why do you think this would solve the problem? This is already wrong because `changePage` is not passed the event object it expects. – Felix Kling Aug 27 '19 at 07:33
-1

change it to arrow function to get "this" instance like in below code,

changePage = (event) => {
   /* here you can access to "this" instance
   eg: this.setState({ pageName:'myPage' )}
  */
}