从 material-ui 的 GridList 中提取属性

Extracting properties from material-ui's GridList

几天前我才开始学习React,所以如果这个问题听起来很愚蠢,请原谅我。

在这项工作任务中,我必须使用 material-ui 的 GridList 实现一个 'Like' 系统。总共会有八张图片,用户可以通过点击喜欢按钮来喜欢它们。在我当前的代码中,用户可以单击“赞”按钮,但所有“赞”按钮都会受到影响,而不仅仅是一个。而且,点赞数并没有增加。

所以我的问题是,当用户单击 'Like' 按钮时,如何更改点赞数并确保只有 1 个按钮受到影响?我已经尝试过 props 甚至 lodash,但我似乎无法找出问题所在。下面是我的 GridList 部分的全部代码。任何帮助将不胜感激。

import _ from 'lodash';
import React from 'react';
import {GridList, GridTile} from 'material-ui/GridList';
import Subheader from 'material-ui/Subheader';
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';

//GridList style
const styles = {
  root: {
    display: 'flex',
    flexWrap: 'wrap',
    justifyContent: 'space-around',
  },
  gridList: {
    width: 1000,
    height: 500,
  },
};

//data for the GridList
var tilesData = [
  {
    img: './images/image_01.jpg',
    title: 'Breakfast',
    likes: 0,
  },
  {
    img: './images/image_02.jpg',
    title: 'Tasty burger',
    likes: 0,
  },
  {
    img: './images/image_03.jpg',
    title: 'Camera',
    likes: 0,
  },
  {
    img: './images/image_04.jpg',
    title: 'Morning',
    likes: 0,
  },
  {
    img: './images/image_05.jpg',
    title: 'Hats',
    likes: 0,
  },
  {
    img: './images/image_06.jpg',
    title: 'Honey',
    likes: 0,
  },
  {
    img: './images/image_07.jpg',
    title: 'Vegetables',
    likes: 0,
  },
  {
    img: './images/image_08.jpg',
    title: 'Water plant',
    likes: 0,
  },
];

export default class Grid extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      like: false,
      likes: tilesData.likes,
    };
    this.post = this.post.bind(this);
    this.delete = this.delete.bind(this);
  }

  //if Like button is clicked
  post(){
      this.setState({ like: true});
      let likes = this.state.likes;
      likes++;
      this.setState({likes: likes});
      //this.tilesData.likes = likes;
  }

  //if Like button is "unclicked"
  delete(){
      this.setState({ like: false});
      let likes = this.state.likes;
      likes--;
      this.setState({likes: likes});
      //this.tilesData.likes = likes;
  }

  getChildContext() {
    return { muiTheme: getMuiTheme(baseTheme) };
  }

  render(){
    const likeBtn = this.state.like ? <img src="./images/icons/icon_2.png" onClick={this.delete} /> : <img src="./images/icons/icon_1.png" onClick={this.post} />;
    return (
      <div style={styles.root}>
        <GridList
          cellHeight={200}
          cols={4}
          style={styles.gridList}
        >
        <Subheader>December</Subheader>
        {tilesData.map((tile) => (
          <GridTile
            key={tile.img}
            title={tile.title}
            subtitle={<span>Likes: <b>{tile.likes}</b></span>}
            actionIcon={likeBtn}
          >
            <img src={tile.img} />
          </GridTile>
          ))}
        </GridList>
      </div>
    );
  }
}

Grid.childContextTypes = {
  muiTheme: React.PropTypes.object.isRequired,
}

问题

'State' of like 按钮在循环外定义意味着相同的 'state' 与所有 GridTile 共享组件(对于所有图像)。

当您单击 'like' 按钮时,您正在更改 Grid 父组件中 'like' 按钮的 'state' 和相同'state' 用于所有 喜欢 按钮。

这就是它影响所有按钮的原因。

解决方案

'state' 应该为每个 like 按钮单独定义。另外 deletepost 方法应该在 GridTile 中的循环方式中定义。

但 GridTile 是 material-ui 库的一部分,因此不要更改此库,而是在 GridTile 组件上创建一个包装器。 网格组件将调用组件让我们说它是循环内的 GridTileCustom 组件。

在 GridTileCustom 组件中,您需要定义 deletepost 方法,您在 'onClick' 中使用事件 所以你的最终代码看起来像

import React from 'react';
  import {GridList, GridTile} from 'material-ui/GridList';
  import Subheader from 'material-ui/Subheader';
  import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
  import getMuiTheme from 'material-ui/styles/getMuiTheme';
  import IconButton from 'material-ui/IconButton';

  const thumbsIcon = "glyphicon glyphicon-thumbs-up";

  const styles = {
  root: {
    display: 'flex',
    flexWrap: 'wrap',
    justifyContent: 'space-around',
  },
  gridList: {
    width: 1000,
    height: 500,
  },
  };

  var tilesData = [
  {
    img: './images/image_01.jpg',
    title: 'Breakfast',
    likes: 0,
    icon: './images/icons/icon_1.png',
  },
  {
    img: './images/image_02.jpg',
    title: 'Tasty burger',
    likes: 0,
    icon: './images/icons/icon_1.png',
  },
  {
    img: './images/image_03.jpg',
    title: 'Camera',
    likes: 0,
    icon: './images/icons/icon_1.png',
  },
  {
    img: './images/image_04.jpg',
    title: 'Morning',
    likes: 0,
    icon: './images/icons/icon_1.png',
  },
  {
    img: './images/image_05.jpg',
    title: 'Hats',
    likes: 0,
    icon: './images/icons/icon_1.png',
  },
  {
    img: './images/image_06.jpg',
    title: 'Honey',
    likes: 0,
    icon: './images/icons/icon_1.png',
  },
  {
    img: './images/image_07.jpg',
    title: 'Vegetables',
    likes: 0,
    icon: './images/icons/icon_1.png',
  },
  {
    img: './images/image_08.jpg',
    title: 'Water plant',
    likes: 0,
    icon: './images/icons/icon_1.png',
  },
  ];

  export default class Grid extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      like: false,
      likes: tilesData.likes,
    };
    // this.post = this.post.bind(this);
    // this.delete = this.delete.bind(this);
  }

  // post(){
  //     this.setState({ like: true});
  //     let likes = this.state.likes;
  //     likes++;
  //     this.setState({likes: likes});
  //     //this.tilesData.likes = likes;
  // }

  // delete(){
  //     this.setState({ like: false});
  //     let likes = this.state.likes;
  //     likes--;
  //     this.setState({likes: likes});
  //     //this.tilesData.likes = likes;
  // }

  getChildContext() {
    return { muiTheme: getMuiTheme(baseTheme) };
  }

  render(){
    return (
      <div style={styles.root}>
        <GridList
          cellHeight={200}
          cols={4}
          style={styles.gridList}
        >
        <Subheader>December</Subheader>
        {tilesData.map((tile) => (
          <GridTileInternal
            key={tile.img}
            img={tile.img}
            title={tile.title}
            subtitle={tile.likes}
            // actionIcon={likeBtn}
          >
          </GridTileInternal>
          ))}
        </GridList>
      </div>
    );
  }
  }

  class GridTileInternal extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      like: false,
      likes: tilesData.likes,
    };
    this.post = this.post.bind(this);
    this.delete = this.delete.bind(this);
  }

  post(){
      this.setState({ like: true});
      let likes = this.state.likes;
      likes++;
      this.setState({likes: likes});
      //this.tilesData.likes = likes;
  }

  delete(){
      this.setState({ like: false});
      let likes = this.state.likes;
      likes--;
      this.setState({likes: likes});
      //this.tilesData.likes = likes;
  }


  render(){
    const likeBtn = this.state.like ? <img src="./images/icons/icon_2.png" onClick={this.delete} /> : <img src="./images/icons/icon_1.png" onClick={this.post} />;
    return (
          <GridTile
            key={this.props.img}
            title={this.props.title}
            subtitle={<span>Likes: <b>{this.props.subtitle}</b></span>}
            actionIcon={likeBtn}
          >
            <img src={this.props.img} />
          </GridTile>
    );
  }
  }

  Grid.childContextTypes = {
  muiTheme: React.PropTypes.object.isRequired,
  }