Реагировать компонент для обновления дочернего компонента - PullRequest
0 голосов
/ 26 января 2019

У меня есть компонент React (Albums), метод render() которого возвращает один из двух возможных компонентов, в зависимости от его состояния.Один из этих компонентов (AlbumsTable) вызывается с двумя параметрами реквизита, classes и albums.Второй параметр props - это массив, полученный ajax с использованием Axios в методе (getData), который обновляет состояние Albums, вызывая его повторный рендеринг.

Из-за асинхронной природы Ajax, Albums рендерит дважды, первый раз с this.albums = [], а второй (вызванный getData() обновлением состояния) с this.albums, равным результату ajax.

Проблема в том, чтоЯ могу проследить, что AlbumsTable.constructor() вызывается только один раз (первый раз Albums рендеринг), когда this.albums равен [].Поэтому во второй раз Albums отображается, когда this.albums равен результату ajax, это содержимое не отправляется как реквизиты на AlbumsTable, в результате чего результат ajax не будет отображаться никогда.

Это код моих компонентов:

import React, { Component } from 'react';
import Cookies from 'js-cookie';
import axios from 'axios';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';

const styles = theme => ({
  root: {
    width: '100%',
    marginTop: theme.spacing.unit * 3,
    overflowX: 'auto',
  },
  table: {
    minWidth: 700,
  },
});

class AlbumsTable extends Component {
  constructor(props) {
    super(props);
    this.state = {
      classes: props.classes,
    }

    if(props.albums === undefined){
      this.albums = [];
    } else {
      this.albums = props.albums;
    }

  }

  render() {
    return (
      <Paper className={this.state.classes.root}>
        <Table className={this.state.classes.table}>
          <TableHead>
            <TableRow>
              <TableCell>ID</TableCell>
              <TableCell align="right">Name</TableCell>
              <TableCell align="right">Photos</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {this.albums.map(album => {
              return (
                <TableRow key={album.id}>
                  <TableCell component="th" scope="row">
                    {album.name}
                  </TableCell>
                  <TableCell align="right">{"photos"}</TableCell>
                </TableRow>
              );
            })}
          </TableBody>
        </Table>
      </Paper>
    );
  }
}

class AlbumDetail extends Component {
  render() {
    return(<p>Album Detail Comming Soon...</p>);
  }
}

class Albums extends Component {
  constructor(props) {
    super(props);

    this.state = {
      classes: props.classes,
      mode: 'table',
      albums: [],
    };
    this.albums = [];
    this.getData();
  }

  getData() {
      const axios = require('axios');
      var userToken = Cookies.get('token');
      axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
      axios.defaults.xsrfCookieName = "csrftoken";
      axios.get('http://127.0.0.1:8000/es/api/albums/',
        {
          headers: {
            Authorization: userToken,
          }
        }
      )
      .then(function (response) {
        console.log(response);
        this.albums = response.data.results;
        this.setState({albums: this.state.albums + 1});
      }.bind(this))
      .catch(function (error) {
        console.log(error);
        return(null);
      })
    }

  setData(albums) {
    this.setState({albums: albums});
  }

  render() {  
    if(this.state.mode === 'table'){
      return (<AlbumsTable classes={this.state.classes} albums={this.albums} />);
    } else {
      return (<AlbumDetail />);
    }

  }
}

Albums.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(Albums);

Полагаю, я что-то упускаю или неправильно понимаю, что такое рендеринг компонентов.

Ответы [ 2 ]

0 голосов
/ 26 января 2019

если вы считаете свою проблему лучше, вы можете понять, что вам не нужно сохранять массив albums как переменную в компоненте класса, лучше проверить, определено ли ваше свойство albums, иначе вам следует вернуть пустой массив, таким образом, компонент будет работать как положено.

render(){
    const albums = this.props.albums || [];
    return (
       <Paper className={this.state.classes.root}>
        <Table className={this.state.classes.table}>
          <TableHead>
            <TableRow>
              <TableCell>ID</TableCell>
              <TableCell align="right">Name</TableCell>
              <TableCell align="right">Photos</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {albums.map(album => {
              return (
                <TableRow key={album.id}>
                  <TableCell component="th" scope="row">
                    {album.name}
                  </TableCell>
                  <TableCell align="right">{"photos"}</TableCell>
                </TableRow>
              );
            })}
          </TableBody>
        </Table>
      </Paper>
    );
  }
0 голосов
/ 26 января 2019

Компонент повторного рендеринга не будет вызывать его повторное создание. Вместо этого он будет обновлен, поэтому constructor не будет срабатывать дважды. Это стандартное поведение. Вы должны использовать static getDerivedStateFromProps метод для обновления состояния в ответ на изменение реквизита. Вы можете найти больше информации здесь: https://reactjs.org/docs/react-component.html#the-component-lifecycle

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...