简体   繁体   中英

How does ES6 class instance variable work

I have the following code which is working as expected:

import React, { Component } from 'react';

let result = null;
class MyData extends Component {
  _getData = () => {
    fetch(url)
      .then(response => response.json())
      .then(data => {
        result = items.find(
          item => item.id === 'abcd'
        );
      });
  };

  componentDidMount() {
    this._getData();
  }

  render() {
    return result ? <span>hello</span> : null;
  }
}

When I try to move result as an instance variable of the class as follows, it always remains null in the render() method. Though the assignment is working correctly post fetch:

import React, { Component } from 'react';

class MyData extends Component {
  result = null;
  _getData = () => {
    fetch(url)
      .then(response => response.json())
      .then(data => {
        this.result = items.find(
          item => item.id === 'abcd'
        );
      });
  };

  componentDidMount() {
    this._getData();
  }

  render() {
    return this.result ? <span>hello</span> : null;
  }
}

Can someone explain me what is the expected usage here. And how things have changed from ES6 onwards.

Both examples just don't work, the reason is that componentDidMount lifecycle fires after render lifecycle .

Because you don't cause re-render (with setState ) in any phase, nothing will cause an additional render to read the updated value of result .

在此处输入图片说明

Therefore, the next example will always render No Result

import ReactDOM from 'react-dom';
import React, { Component } from 'react';

let result = null;

class App extends Component {
  thisResult = null;
  setResult = () => {
    result = 10;
    this.thisResult = 10;
  };

  componentDidMount() {
    this.setResult();
  }

  render = () => {
    return <div>{result || this.thisResult ? 'Result' : 'No Result'}</div>;
  };
}

ReactDOM.render(<App />, document.getElementById('root'));

编辑华丽的雪花-u4s6x

The reason you are seeing null is because the state is not being updated in the code example you posted. The component mounts and this.result is null. But when the _getData method is called and the response comes back, the component is not being rendered.

You should be storing this data in your state, as React relies on the state changes to know when it should re-render the component. Try something like this:

import React, { Component } from 'react';

class MyData extends Component {
  state = {
    result: null
  }
  _getData = () => {
    fetch(url)
      .then(response => response.json())
      .then(data => {
        this.setState({
          result: items.find(
            item => item.id === 'abcd'
          )
        })
      });
  };

  componentDidMount() {
    this._getData();
  }

  render() {
    const { result } = this.state
    return result ? <span>hello</span> : null;
  }
}

You can learn more about rendering, state, and component lifecycles here: https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class

Edit: If you want to experiment with the new react hooks api, you could convert your component to look like the folllowing:

import React, { useEffect, useState } from 'react';

const MyData = ({ ...props }) => {
  const [result, setResult] = useState(null);

  const getData = () => {
    fetch(url)
      .then(response => response.json())
      .then(data => {
        const result = items.find(item => item.id === 'abcd');

        setResult(result);
      });
  };

  useEffect(() => {
    getData();
  }, []);

  return result ? <span>hello</span> : null;
}

I think the main thing you're missing is state. Keep in mind that these Components you are extending are React Component classes which have a very specific life cycle. Look into component life cycle for more info. This will work as expected with the following refactor:

import React, { Component } from 'react';

class MyData extends Component {
    constructor() {
        super();
        this.state = {result:  null};
    }

    _getData = () => {
        fetch(url)
        .then(response => response.json())
        .then(data => {
            let resp = data.items.find(
                item => item.id === 'abcd'
            );

            this.setState({ result: resp });
        });
    };

    componentDidMount() {
        this._getData();
    }

    render() {
       return this.state.result ? <span>hello</span> : null;
    }
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM