1

I'm trying to learn react and I'm creating a web app with firebase database and auth and the movie db api. I'm able to have a user click on a movie and add that movie to their watchlist "sends info of that movie to firebase". now I'm trying to retrieve that info, and I'm successful in doing so, but my code currently causes the browser to lock up and crashes and keeps logging endlessly and I need to force quit. I'm not sure where I'm going wrong? When I put the code that's in the render in the constructor, or in a componentDidMount, this.props.user returns null. I'm confused :(

app.js constructor

passing state to watchlist component

heres the code:

import React, { Component } from 'react'
import firebase from '../config/Firebase';

import { Container } from 'react-bootstrap';

import WatchlistMovie from './WatchlistMovie';

export default class Watchlist extends Component {
  constructor(props){
    super(props);
    this.state = {
      movies: [],
    }
  }

  render() {

    const movieRef = firebase.database().ref(`watchlist/${this.props.user}`);

    movieRef.on("value", snapshot => {
      let movies = snapshot.val();

      console.log(movies);

      let newState = [];

      for(let movie in movies){
        newState.push({
          id: movies[movie].id,
          title: movies[movie].title,
          rating: movies[movie].rating,
          poster: movies[movie].poster
        });
      }

      this.setState({
        movies: newState
      });

      console.log(this.state.movies);

    });


    return (
      <div>
        <Container>
            <WatchlistMovie
              ... send data from firebase to this individual movie component
            />
        </Container>
      </div>
    )
  }
}
juicy j
  • 183
  • 5
  • 20
  • Can you post the error trace? – Jay Ordway Mar 13 '19 at 04:05
  • no error in terminal, console just keeps logging (this.state.movies) causing browser to crash – juicy j Mar 13 '19 at 04:16
  • 2
    Hi, You can't call setState inside render function as changing the state re-renders the component so you get a infinite loop where your render function calls setState and because of setState your render functions gets called again. You need to take this code and put it in componentDidMount lifecycle function – Rishabh Rawat Mar 13 '19 at 04:18
  • Hey Rishabh, when i put it in a componentDidMount lifecycle, this.props.user is recieved as null – juicy j Mar 13 '19 at 04:20
  • Can you show where the props are being passed? – Jay Ordway Mar 13 '19 at 04:25
  • @juicyj How are you passing user prop in the component? Can you show us a piece of code for that? – Rishabh Rawat Mar 13 '19 at 04:46
  • @JayOrdway Rishabh Rawat i attached 2 images above from my app js, the constructor of with the state, and the component im passing the info to – juicy j Mar 13 '19 at 04:48
  • when i check the component "Watchlist" in my react developer tool i can see the user prop – juicy j Mar 13 '19 at 04:49
  • @juicyj I want to know how are you passing user prop to Watchlist component. I think the parent component where you are calling Watchlist problem is passing user prop as null initially and after loading user data it is passing the user value again. You need to write a check for that like this `{this.state.user && < Watchlist user={user} />}` – Rishabh Rawat Mar 13 '19 at 04:51
  • @juicyj and after that you can move your code from render to componentDidMount and it will work – Rishabh Rawat Mar 13 '19 at 04:53
  • OMG that worked!!! thank you SO much Rishabh!!! Do you have any resources on those "checks" that i can read up more on? – juicy j Mar 13 '19 at 04:56
  • @juicyj Sure, You can use this link https://reactjs.org/docs/conditional-rendering.html and also please accept my solution if it worked for you :) – Rishabh Rawat Mar 13 '19 at 04:56
  • id love to accept your solution! (im not too sure how im not too used to stack overflow lol) – juicy j Mar 13 '19 at 04:58
  • @juicyj click the up arrow button above the flag button on the left side of my comment – Rishabh Rawat Mar 13 '19 at 04:59

1 Answers1

1

render() {...} is not the place to fetch data. Move it to componentDidMount as below:


export default class Watchlist extends Component {
  constructor(props){
    super(props);
    this.state = {
      movies: [],
    }
  }

  componentDidMount() {
    const movieRef = firebase.database().ref(`watchlist/${this.props.user}`);

    movieRef.on("value", snapshot => {

      // I keep your logic here
      let movies = snapshot.val();

      console.log(movies);

      let newState = [];

      for(let movie in movies){
        newState.push({
          id: movies[movie].id,
          title: movies[movie].title,
          rating: movies[movie].rating,
          poster: movies[movie].poster
        });
      }

      this.setState({
        movies: newState
      });



    });
  }

  render() {

    const { movies } = this.state;


    return (
      <div>
        <Container>
            <WatchlistMovie
              ... send data from firebase to this individual movie component
            />
        </Container>
      </div>
    )
  }
}

Ponleu
  • 1,492
  • 12
  • 27