MihinduGajaba
MihinduGajaba

Reputation: 21

React components not re-rendering on firebase child_update event

I've written a basic React + Firebase application just to identify how it works.

I have a react component(ViewPosts) which returns a list of react components(Post) based on the returned data-set from Firebase database.

I've attached the Firebase events child_removed, child_added and child_changed on componentDidMount()

All the events that I'm attaching is working fine but only the child_changed event is not re-rendering the page. but I've added a console.log just to check if the event is triggered and it is. ( I'm updating/removing the values using the firebase console)

I thought it might be an issue with the keys so i even added an index to make it unique but still no luck.Am I missing something here ? Why is the code giving me this behavior.

Since React update only the updated components, list will not update even if I removed or added a new component to the list, but if i removed one component and that component happens to be a one above the updated component(Post) then since React is forced to re-render the list below that component I can see the updated value.

Please help me to identify why this is happening

ViewPosts

import React, { Component } from 'react';
import * as firebase from 'firebase';
import Post from './Post';

var listItems = null;
var starCountRef = null;
class ViewPosts extends Component {

  constructor(props) {
   super(props);
   this.state = {renderedList: []};
   this.getDatafromDB = this.getDatafromDB.bind(this);
   starCountRef = firebase.database().ref('posts');
  }

  getDatafromDB() {
    listItems = [];
    starCountRef.once('value', snapshot => {
      var results = snapshot.val();
      var resultsKeys = Object.keys(results);
      listItems = resultsKeys.map((key,i) => <Post key={key.toString() + i} value={results[key].value + i } />);

      this.setState({
        renderedList : listItems
      });
    });
  }
  componentDidMount(){

    // Get the data on a post that has been removed
    starCountRef.on("child_removed", snapshot =>  {
      var deletedPost = snapshot.val();
      console.log("The post valued '" + deletedPost.value + "' has been deleted");
      this.getDatafromDB();
    });

    // Get the data on a post that has been removed
    starCountRef.on("child_added", snapshot =>  {
      var addedPost = snapshot.val();
      console.log("The post value '" + addedPost.value + "' has been added");
      this.getDatafromDB();
    });

    starCountRef.on("child_changed", snapshot =>  {
      var changedPost = snapshot.val();
      console.log("The updated post value is " + changedPost.value);
      this.getDatafromDB();
      console.log("this.state.listItems " + this.state.renderedList);
    });

  }
   render() {
   return(
     <div>
      <ul>
        {this.state.renderedList}
      </ul>
      </div>
   );
 }
}

export default ViewPosts;

Post

import React, { Component } from 'react';

class Post extends Component {

  constructor(props) {
   super(props);
   this.state = {value: props.value};
  }

 render() {
   return(
     <li>{this.state.value}</li>
   );
 }
}

export default Post;

Upvotes: 2

Views: 1829

Answers (2)

Sowmiya Sridharan
Sowmiya Sridharan

Reputation: 11

Clone your object and then set the state

const clonelistItems = listItems.slice();
this.setState({
    renderedList :clonelistItems
});

Upvotes: 1

MihinduGajaba
MihinduGajaba

Reputation: 21

I Introduced a new property "uid" and mapped that UID to the Key of the component. Then when i update the both the UID and the value , React picked it up as a update and re-rendered that component.

Even though that I've included the index to the key until i remove one component above that key will be the same and that explains the reason why it's re-rendered when i removed a component from top.

Basically if there's multiple component of the same type those has to be tied with a unique key and unless that key changed React will not re-render the component even though the value is changed.

As far as i know what React do is in background create a virtual DOM and compares it with the existing one and only re-render the changed components. and seems like when doing so it looks for the key if there's multiple and if its the same it skips the whole component

Also In case if you wonder how i created a key i generated one using lodash's _.uniqueId([prefix='']) method

Thanks,

Upvotes: 0

Related Questions