skip to Main Content

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 })
  }
}

2

Answers


  1. 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.

    Login or Signup to reply.
  2. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search