Lista los comentarios de un artista trayendo los datos desde Firebase

Clase 26 de 36Curso de React Native 2016

Resumen

Ya tenemos los comentarios en nuestra base de datos, pero aún no los estamos viendo en nuestra pantalla. Vamos a listarlos en la la vista de detalle del artista en tiempo real.

Para eso, vamos a crear un nuevo archivo llamado CommentList, copiando lo que ya hemos hecho para listar los artistas en ArtistList:

import React, { Component } from 'react';
import {
  StyleSheet,
  ListView,
} from 'react-native';

export default class CommentList extends Component {
  
  constructor(props) {
    super(props);
    const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => {
      r1 !== r2
    }})
    this.state = {
      dataSource: ds
    }
  }

  componentDidMount() {
    this.updateDataSource(this.props.comments)
  }

  componentWillReceiveProps(newProps) {
    if (newProps.comments !== this.props.comments) {
      this.updateDataSource(newProps.comments)
    }
  }

  updateDataSource = (data) => {
    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(data)
    })
  }

  render() {
    return (
      true}
        dataSource={this.state.dataSource}
        renderRow={(comment) => {
          return 
        }}
      />
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'lightgray',
    paddingTop: 50,
  },
});

Y vamos a utilizarlo dentro de nuestro componente de ArtistDetailView, importándolo y definiendo un state inicial para el listado de comentarios:

...
import CommentList from './CommentList'

export default class ArtistDetailView extends Component {
  state = {
    comments: []
  }
  …
  render() {
    const artist = this.props.artist
    const { comments } = this.state

    return (
      
        
        
        
          "Opina sobre este artista"
            onChangeText={this.handleChangeText}
          />
          this.handleSend}>
            "ios-send-outline" size={30} color="gray" />
          
        
      
    );
  }
}

Para que esto funcione, debemos crear un nuevo componente llamado Comment.js y veremos cómo definir componentes sencillos, devolviendo sólo una función:

import React from 'react'
import {
  Text
} from 'react-native'

const Comment = (props) => {props.text}

export default Comment

Ahora debemos escuchar cambios en Firebase, para saber cuándo se produce un nuevo comentario y mostrarlo en la pantalla en nuestro componente de ArtistDetailView:

componentDidMount() {
    this.getArtistCommentsRef().on('child_added', (data) => {
      const comment = data.val()
      this.setState({
        comments: this.state.comments.concat(comment)
      })
    })
  }

Lo probamos y vemos que nos trae los comentarios para cada artista.
Si escribimos un nuevo comentario, volvemos a la pantalla del listado y volvemos a entrar al detalle del artista, vemos que sólo lista el nuevo comentario. Para evitar este tipo de errores de suscripción de eventos en memoria, debemos reescribir un poco ese método y agregar el método componentWillUnmount que se llamará cuando el componente vaya a desaparecer de la vista:

componentDidMount() {
    this.getArtistCommentsRef().on('child_added', this.addComment)
  }

  addComment = (data) => {
    const comment = data.val()
    this.setState({
      comments: this.state.comments.concat(comment)
    })
  }

  componentWillUnmount() {
    this.getArtistCommentsRef().off('child_added', this.addComment)
  }

Vamos a agregar a continuación un poco de estilos para nuestro componente Comment:

import React from 'react'
import {
  StyleSheet,
  Text,
  View
} from 'react-native'

const Comment = (props) => 
  
    {props.text}
  

const styles = StyleSheet.create({
  comment: {
    backgroundColor: '#ecf0f1',
    padding: 10,
    margin: 5,
    borderRadius: 5
  },
  text: {
    fontSize: 16
  }
})

export default Comment

Y un título para separar al artista de los comentarios en el ArtistDetailView con sus estilos correspondientes, importando el componente de Text de 'react-native':

Comentarios
...
header: {
    fontSize: 20,
    paddingHorizontal: 15,
    marginVertical: 10
  }

Para poder limpiar el Input una vez que se haga un comentario, debo agregar esta línea al handleSend para limpiar el text en el estado:

handleSend = () => {
    ...
    this.setState({ text: '' })
  }

Y decirle en el render que el value del Input debe ser tomado del state del componente:

render() {
    const artist = this.props.artist
    const { comments } = this.state

    return (
         ... 
          this.state.text}
            placeholder="Opina sobre este artista"
            onChangeText={this.handleChangeText}
          />
          … 
    );
  }

Vemos que tenemos un error en nuestra UI ya que el TextInput está tapando al último comentario agregado, cuando el listado de comentarios llega al final de la pantalla. Como ahora tenemos un componente en el medio que es el listado de comentarios, no hace falta posicionarlo absolutamente al TextInput, asi que quitamos estas líneas de sus estilos:

position: 'absolute',
bottom: 0,
right: 0,
left: 0,

Con esto nuestra UI queda bellísima.

Encontrarás un desafío para corregir el número de comentarios que tiene un artista, haciendo algo similar a lo que hicimos con los likes.