0

I'm trying to navigate between a master detail data format in React. The source page does this:

{myDataList.map(myData =>
    <tr key={myData.dataId}>
    <td>{myData.dataId}</td>
    <td>{myData.dataDescription}</td>
    <td>
        <NavLink to={'/details/' + myData.dataId}>
            Details
        </NavLink>
    </td>

Clicking the edit link does navigate to the details page with the correct URL; which does this (mainly taken from the example template in VS):

interface DetailsState {
    details?: DataDetails;
    loading: boolean;
}

export class Details extends React.Component<RouteComponentProps<number>, DetailsState> {
constructor() {
    super();
    this.state = { details: undefined, loading: true };

    console.log("match params: " + this.props.match.params);

    fetch('api/Data/Details/' + this.props.match.params)
        .then(response => response.json() as Promise<DataDetails>)
        .then(data => {
            this.setState({ details: data, loading: false });
        });
}

My problem is that the console.log like above shows:

TypeError: _this.props is undefined

And so I can't access the dataId that I'm passing through.

Clearly I'm passing (or receiving) this parameter incorrectly; so my question is: what is the correct way to pass the parameter? It's worth noting that my project is based on the VS Template, and I am using tsx, rather than jsx files.

1

2 Answers 2

2

You cannot access this.props in a component's constructor. However, it is available as the first parameter. You can do this:

export class Details extends React.Component<RouteComponentProps<number>, DetailsState> {
  constructor(props) {
    super(props);
    this.state = { details: undefined, loading: true };

    console.log("match params: " + props.match.params);

    fetch('api/Data/Details/' + props.match.params)
      .then(response => response.json() as Promise<DataDetails>)
      .then(data => {
        this.setState({ details: data, loading: false });
      });
  }
}

Make sure that you call super(props) as the first thing in the constructor, or else React will yell at you.

EDIT:

As @Dan notes, it's generally not avisable to perform asynchronous actions in the constructor. Better to do that in componentDidMount():

export class Details extends React.Component<RouteComponentProps<number>, DetailsState> {
  constructor(props) {
    super(props);
    this.state = { details: undefined, loading: true };

    console.log("match params: " + props.match.params);
  }

  componentDidMount() {
    fetch('api/Data/Details/' + this.props.match.params)
      .then(response => response.json() as Promise<DataDetails>)
      .then(data => {
        this.setState({ details: data, loading: false });
      });
  }
}
Sign up to request clarification or add additional context in comments.

9 Comments

You shouldn't do network requests in the constructor. It's encouraged to do so in componentDidMount().
Yes, that's definitely true. I was aiming to give the minimal edits possible to answer @pm_2's question. But I will add a clarification.
Because it's typescript - it wants a type for props, but as far as I'm concerned - props is just a number?
Regarding the network request - that's straight from the MS template
Thanks for your help - I managed to get this to work by defining an interface that contains a single property of ID
|
1

If you want to access props in your constructor, you need to pass them in:

constructor(props) {
    super(props);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.