3

I bundle the codes with ./node_modules/.bin/webpack -d. I didn't compile ES6 to ES5 except this class fields proposal.

It give this error:

Uncaught TypeError: this.fetchTestExecutions is not a function

Here's the codes:

import React from 'react'
import Config from 'Config'

class HomePage extends React.Component {

  state = {
    executions: this.fetchTestExecutions()
  }

  fetchTestExecutions = () => {
    const host = Config.host
    return fetch(`${host}/execution/index`)
      .then(response => response.json())
      .then(json => {
        this.setState({executions: json})
      })
  }

  render() {
    return(
      <div>
        { this.state.executions.map(x => <div>x.from</div>) }
      </div>
    )
  }
}

export default HomePage

Here's the webpack.config.js:

var webpack = require('webpack')

module.exports = {
  entry: './src/App.jsx',
  output: {
    filename: './../public/bundle.js'
  },
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        query: {
          plugins: ['transform-class-properties'],
          presets: ['react'],
        }
      }
    ]
  },
  externals: {
    'Config': JSON.stringify({host: "http://127.0.0.1:3000"})
  }
}

What's wrong?

Thanks for your time!

mCY
  • 2,731
  • 7
  • 25
  • 43

3 Answers3

3

Setting a method (specially an api call) as a state property is not a good pattern. Instead, prefer calling the api first in a lifecycle event and then set state later.

class HomePage extends React.Component {
  state = {
    executions: []
  }

  componentDidMount() {
    const host = Config.host

    fetch(`${host}/execution/index`)
      .then(response => response.json())
      .then(json => this.setState({ executions: json }))
  }

  render() {
    return(
      <div>
        { this.state.executions.map(x => <div>x.from</div>) }
      </div>
    )
  }
}
Hemerson Carlin
  • 7,354
  • 1
  • 27
  • 38
  • 5
    He's not setting the method, he's setting the promise returned from that method. However, it's definitely a very bad pattern. – Sulthan Jan 19 '18 at 06:57
  • Yes, sure. It was just a mean to explain the bad pattern :) – Hemerson Carlin Jan 19 '18 at 07:03
  • Hi @mersocarlin, thanks for the advise on setting state. what if I got another `randomString = () => "a string"`, and `state = { executions: this.randomString()}`. It still give the same error. `state` is a class variable? `this.randomString()` is instance method? – mCY Jan 19 '18 at 07:29
  • @mCY `state` is an object [link to docs](https://reactjs.org/docs/faq-state.html). And I wouldn't use method (as `randomString` for example) to set its initial properties. `this.randomString()` is an instance method if you defined it inside your component (which allows you to call `this.randomString()`) from anywhere within the component. – Hemerson Carlin Jan 19 '18 at 07:46
2

Class fields (which are currently stage 2 proposal) are assigned on class instantiation. The original code is equal to this ES6 code:

class HomePage extends React.Component {
  constructor() {
    this.state = {
      executions: this.fetchTestExecutions()
    };

    this.fetchTestExecutions = () => { /*...*/ };
  }
  ...
}

As it appears, the order matters, and fetchTestExecutions is undefined at the moment when it's being called.

In order to make it work, fetchTestExecutions class field should be defined before state.

Unless fetchTestExecutions is used as a callback (and it's not), it should definitely be prototype method (already suggested in another answer):

class HomePage extends React.Component {
  state = {
    executions: this.fetchTestExecutions()
  }

  fetchTestExecutions() { /*...*/ }
  ...
}

This eliminates the problem and results in more efficient code. See also this explanation on what are the practical differences between arrow (instance) and prototype methods.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
1

You have to change your function like this

fetchTestExecutions(){
const host = Config.host
return fetch(`${host}/execution/index`)
  .then(response => response.json())
  .then(json => {
    this.setState({executions: json})
  })
}
Rajat Dhoot
  • 185
  • 3
  • 17