ark9719
ark9719

Reputation: 1

State updates but does not render

I am new to ReactJS and am unsuccessfully attempting to manage a state change. The initial state renders as expected, the state successfully changes, however the elements do not render afterwards. There are no errors in the DOM console to go off of. I've made sure to set the initial state in the constructor of the component class, and I've also tried binding the method I'm using in the constructor since I've read auto-binding is not a part of ES6. The relevant component code is as follows:

class MyComponent extends Component {
    constructor(props) {
        super(props);
            this.state = {
                myIDs: Array(6).fill('0')
        };
        this.getMyIDs = this.getMyIDs.bind(this);

};

componentDidMount() {
    var ids = this.getMyIDs();
    ids.then((result)=> {
        this.setState({ myIDs: result }, () => {
            console.log(this.state.myIDs)
        });
    })

};

componentWillUnmount() {
    this.setState({
        myIDs: Array(6).fill('0')
    });
};

getMyIDs() {
    return fetch('/api/endpoint').then((response) =>{
        return response.json();
    }).then((myIDs) => {
        return myIDs.result
    })
};

render() {
    return (
        <Tweet tweetId={this.state.myIDs[0]} />
        <Tweet tweetId={this.state.myIDs[1]} />
        );
   }
}

export default MyComponent

UPDATE: The 'element' being updated is the 'Tweet' component from react-twitter-widgets. Its source is here:

https://github.com/andrewsuzuki/react-twitter-widgets/blob/master/src/components/Tweet.js'

export default class Tweet extends React.Component {
  static propTypes = {
    tweetId: PropTypes.string.isRequired,
    options: PropTypes.object,
    onLoad: PropTypes.func,
  };

  static defaultProps = {
    options: {},
    onLoad: () => {},
  };

  shouldComponentUpdate(nextProps) {
    const changed = (name) => !isEqual(this.props[name], nextProps[name])
    return changed('tweetId') || changed('options')
  }

  ready = (tw, element, done) => {
    const { tweetId, options, onLoad } = this.props

    // Options must be cloned since Twitter Widgets modifies it directly
    tw.widgets.createTweet(tweetId, element, cloneDeep(options))
    .then(() => {
      // Widget is loaded
      done()
      onLoad()
    })
  }

  render() {
    return React.createElement(AbstractWidget, { ready: this.ready })
  }
}

Upvotes: 0

Views: 117

Answers (2)

Shubham Khatri
Shubham Khatri

Reputation: 281676

The only issue that is present in your current code is that you are returning multiple Element component instances without wrapping them in an array of a React.Fragment or a wrapper div. With the latest version of react, you must write

render() {
    return (
        <React.Fragment>
           <Element Id={this.state.myIDs[0]} />
            <Element Id={this.state.myIDs[1]} />
        </React.Fragment>
        );
   }
}

Also as a practice you must have your Async calls in componentDidMount instead of componentWillMount as the React docs also suggest. You might want to read this answer on where write async calls in React for more details

Another thing that you must remember while using prop Id in your Element component is that componentWillMount and componentDidMount lifecycle functions are only called on the initial Render and not after that, so if you are using this.props.Id in one of these function in Element component then you will not be able to see the update since the result of async request will only come later, check this answer on how to tacke this situation

Upvotes: 0

Tzook Bar Noy
Tzook Bar Noy

Reputation: 11677

As in React docs:

componentWillMount() is invoked just before mounting occurs. It is called before render(), therefore calling setState() synchronously in this method will not trigger an extra rendering. Generally, we recommend using the constructor() instead.

Avoid introducing any side-effects or subscriptions in this method. For those use cases, use componentDidMount() instead.

you should not use ajax calls in componentWillMount call ajax inside: componentDidMount

another thing: why do you use componentWillUnmount

the object will be removed no reason to have that call there.

Upvotes: 2

Related Questions