0

I have a react component which looks like this.

import React, { PropTypes, Component } from 'react';
import { Accordion, Panel, PanelGroup, Table } from 'react-bootstrap';


const FormCell = ({ data }) => (
  <div>
    <a className="pdf-name" onClick={this.doSomething}>{data.item.extension.nameCodeDes}</a>
  </div>
);

class Docs extends Component {
  constructor(props) {
    super(props);
    this.doSomething= this.doSomething.bind(this);
  }

  doSomething() {
    setTimeout(() => {
      console.log("here we are");
    })
  }

  // ...
}

Docs.defaultProps = {
  tableData: null,
  cols: null,
  metaData: {
    documentsColumnMetaData: [
      {
        displayName: 'Policy/Account',
        columnComponent: {
          component: FormCell,
          actions: [],
        },
      },
    ],
  },
};

export default Docs;

The this.doSomething is transpiled to undefined.doSomething in dev tools. I get an error Cannot read property 'downloadDocument' of undefined. Can someone please let me know what I'm missing here? P.S FormCell does more that what is posted. I reduced the code for simplicity

loganfsmyth
  • 156,129
  • 30
  • 331
  • 251
endtoend6
  • 65
  • 1
  • 11
  • 1
    Not sure I understand your question... where are you seeing `undefined.doSomething`? Are you talking about your `FormCell` component, where you're referencing `this.doSomething`? If so, then that makes sense, since it looks like you're trying to reference a class instance property using `this` from outside the context of that class instance. – Kryten Dec 16 '16 at 00:12
  • console says "Cannot read property 'downloadDocument' of undefined" – endtoend6 Dec 16 '16 at 00:16
  • If the error message is referring to a property that's not in the source you posted, that's a pretty good indication that you've removed too much from your source. – Kryten Dec 16 '16 at 00:23
  • I meant to console says "Cannot read property 'doSomething' of undefined" – endtoend6 Dec 16 '16 at 00:24
  • That makes no sense. What value do you expect `this` to refer to inside `FormCell`? – Felix Kling Dec 16 '16 at 02:00
  • You should definitely have a look at [Arrow Functions and This](http://stackoverflow.com/q/28798330/218196). – Felix Kling Dec 16 '16 at 02:06
  • This whole thing just looks like your doing it wrong – DiverseAndRemote.com Dec 16 '16 at 02:53

3 Answers3

0

Arrow functions do not have a this, instead this falls through to the upper scope. I'm not sure why it's undefined in this specific case, but this isn't territory you want to be in normally. Looking at this code I would guess this would be the global object, but maybe a top level arrow function referencing this is supposed to behave this way.

If you want to bind the function, define it with the function keyword instead.

function FormCell({ data }) {
    return <div>
        <a className="pdf-name" onClick={this.doSomething}>{data.item.extension.nameCodeDes}</a>
    </div>;
}
Andy Ray
  • 30,372
  • 14
  • 101
  • 138
0

To expand on the comment I made above...

You've got two different components in your code example: FormCell and Docs. There appears to be no relationship between them, except that you're referring to an undefined this.doSomething function in the FormCell component, which happens to have the same name as a doSomething function declared as a method on the Docs component. This leads me to think that they are supposed to be the same function.

So, working from that assumption...

The this.doSomething function referred to in FormCell should refer to a FormCell.doSomething function. After all, this.doSomething is being called from within the function that's rendering a FormCell component - it should refer to FormCell then. But you haven't defined a doSomething function on the FormCell component, so there's nothing for it to refer to (and you should be getting a "doSomething is not a function" or "doSomething is undefined" error).

If it is your intention to have the this.doSomething in the FormCell refer to the doSomething function on an instance of the Docs component, then you'll need to pass that function in to the FormCell component as a prop.

Kryten
  • 15,230
  • 6
  • 45
  • 68
  • *"that's rendering a `FormCell` component - it should refer to `FormCell` then"* `this` never refers to the function itself, so that conclusion doesn't make sense to me, but sure, maybe the OP thought that would be the case. – Felix Kling Dec 16 '16 at 02:02
  • Thank you very much for that Kryten! ` const FormCell = ({ data }) => (
    {data.item.extension.nameCodeDes} { order: 1, columnName: 'forms', displayName: 'Documents', columnComponent: { component: , actions: [], },`
    – endtoend6 Dec 16 '16 at 02:09
  • @FelixKling - yes, I was more-or-less trying to explain it from the OP's point of view... but it came out somewhat unclear. I'll revise it later when I have a bit more time. – Kryten Dec 16 '16 at 04:57
0

This looks like you're doing it wrong but I'll still answer your question directly. The issue here is that you are defining FormCell outside of Docs but you expect this to be an instance of Docs. What you can do is

change it to:

const FormCell = ({ data, doSomething }) => (
    <div>
        <a className="pdf-name" onClick={doSomething}>{data.item.extension.nameCodeDes}</a>
    </div>
);

And then I assume that you omitted some code inside the Docs component that looks like this

const ColumnComponent = this.props.metaData.documentsColumnMetaData[ 0 ].columnComponent.component;
return <ColumnComponent data={ someData } doSomething={ this.doSomething } />;

Notice how I added the doSomething={ this.doSomething }. That will allow you to pass the doSomething method to the FormCell component as a prop.

DiverseAndRemote.com
  • 19,314
  • 10
  • 61
  • 70