1

How should I parse this using lifecycle methods?

{"blocks":[{
  "key":"33du7",
  "text":"Hello there!",
  "type":"unstyled",
  "depth":0,
  "inlineStyleRanges":[],
  "entityRanges":[],
  "data":{}}],
  "entityMap":{}
}

I want to render the text in my component but I don't know why it throws undefined error. How should I call it?

This is my component:

class Blog extends Component{

constructor(props){
    super(props);
    this.blogContent = props.blogContent;
    this.blogId = props.blogId;

    this.handleRemoveBlog = this.handleRemoveBlog.bind(this);
    this.state = {
        blog__: '',
    };

}

handleRemoveBlog(blogId){
    this.props.removeBlog(blogId);
}

This is my lifecycle method , I would use this.setState but first of all it's giving undefined in console.

   componentWillMount(){
      this.state.blog__ = JSON.parse(this.blogContent);
      console.log(this.state.blog__.text);    // this gives undefined     
  } 

This is the render part.. The data is coming from Firebase. And {this.blogcontent} gives that json string that I previously mentioned.

render(props) {
    return(
        <div className = "blog header">
            <p>{this.blog__.text}</p>

        </div>
    );
}
 }

 Blog.proptypes = {
    blogContent: Proptypes.string
 }
3
  • 1
    Please include the code that you have written to attempt using this object. Commented May 25, 2018 at 12:47
  • @brandNew is right. Simple answer - just based on your comments - use componentWillMount() and maybe also componentWillUpdate() Commented May 25, 2018 at 12:52
  • Sorry , I have updated it now. Now can you tell me where I'm going wrong? Commented May 25, 2018 at 13:00

3 Answers 3

2

This would mostly depend on where you are getting this object from. If it is fetched over the network then the best place to pass it is in the componentDidMount. The reason for this is that the alternative lifecyle method (componentWillMount) does not guarantee a re-render of your component since it does not wait for async actions to finish execution before passing control down to your render method. Hence componentDidMount is best because as soon as new props are received or state is changed it will trigger a re-render. However, if this object is pulled from within the application then chances are, it will work just fine even if pulled within componentWillMount. This is because that operation would be much quicker, so much that control would be passed down to the render method with the new props. This is not guaranteed especially if you want to set state in the process (setting state is also async, so control might execute the rest of the code before all the required data is received).

In short, pass this to componentDidMount and in your render function, before accessing this prop, make sure that it exists. That is, instead of

render() {
 return <div>{this.props.theObject.blocks[0].key}</div>
}

rather do:

render() {
 return <div>{this.props.theObject && this.props.theObject.blocks[0].key}</div>
}

This is how you would do it (assuming you are getting the file over the network using axios)

componentDidMount() {
   axios.get('url/to/the/file')
     .then(fileData => this.setState({
       data: fileData
     });
}
render() {
  // return whatever you want here and setting the inner html to what the state holds
} 
Sign up to request clarification or add additional context in comments.

4 Comments

So what should I write in componentDidMount if I want to get the text in that json string
What does this line means - this.props.theObject && this.props.theObject.blocks[0].key
It's lazy evaluation. Javascript and most other programming languages use it. What it does is evaluate the first expression, if the first expression is false it returns false because whether or not the following expression is true the end result is false because the two expressions are connected by an ampersand (&&). For example false && true returns false. While false || true returns true.
Thanks , got it :)
1

You should not modify the state using

  this.state.blog__ = JSON.parse(this.blogContent);

The proper way to do it is using the this.setState() method:

  this.setState({blog__: JSON.parse(this.blogContent)})

Then, to ensure that the component will be re-rendered, use the method shouldComponentUpdate():

shouldComponentUpdate(nextProps,nextState) {
    if(nextState != this.state) {
        this.forceUpdate()
    }
}

Take a look at the State and Lifecycle docs.

Other point: Use componentDidMount() instead of componentWillMount(), because it will get deprecated in the future.

Atention: The setState() is an asynchronous method. So, it won't instant update your state.

Comments

1

Use this.setState({}) in your componentWillMount function instead assign the data to the variable. Also I recommend to use componentDidMount instead of componentWillMount because it's getting deprecated in the future.

  componentDidMount(){
      let text = JSON.parse( this.blogContent );
      this.setState({blog__: text });     
  } 

Edit: Only use setState in componentDidMount according to @brandNew comment

5 Comments

Using setState might not be a good idea since it is not a guarantee that the state will be set before the render method is executed. Also, the same goes for ComponentWillMount
@brandNew That should not be the problem. Render function will then called twice.
It is actually a problem because you are saying the poster must setState in ComponentWillMount. That's definitely a problem since it is not guaranteed that setState will finish before control is passed over to the next function
Ahh then is that problem. But you should always use componentDidMount()
Look at the first line of your answer. "Use this.setState({}) in your componentWillMount"

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.