反应:子组件中的切换功能无法正常工作

时间:2018-08-07 22:55:58

标签: javascript reactjs

本质上,我试图创建一个复选框UI —我试图传递一个供列表组件使用的切换功能。但是由于某种原因,我可以传播检查但不能取消检查。

这是我的代码:

这是“父母(家庭)”组件:

import React from 'react';
import RecipeDetail from './RecipeDetail';
import RecipeList from './RecipeList';

class Home extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      recipes: [],
      favorites: [],
      currentRecipe: null,
    };
    this.onRecipeClick = this.onRecipeClick.bind(this);
    this.toggleFavorite = this.toggleFavorite.bind(this);
  }

  componentDidMount() {
    fetch(`${API_URL}/v1/recipes`)
      .then(res => res.json())
      .then(recipes =>
        this.setState({
          recipes,
        })
      );
  }

  onRecipeClick = id => {
    fetch(`${API_URL}/v1/recipes/${id}`)
      .then(res => res.json())
      .then(recipe =>
        this.setState({
          currentRecipe: recipe,
        })
      );
  };

  toggleFavorite = id => {
    this.setState(({ favorites, ...state }) => {
      const idx = favorites.indexOf(id);
      if (idx !== -1) {
        return { ...state, favorites: favorites.filter(f => f.id !== id) };
      }
      return { ...state, favorites: [...favorites, id] };
    });
  };

  // prettier-ignore
  render() {
    var { recipes, favorites, currentRecipe } = this.state;
    return (
      <div>
        <main className="px4 flex">
          <RecipeList
            recipes={recipes}
            favorites={favorites}
            style={{ flex: 3 }}
            onClick={this.onRecipeClick}
            onFavorited={this.toggleFavorite}
            />
          <RecipeDetail
            className="ml4"
            recipe={currentRecipe}
            style={{ flex: 5 }}
            />
        </main>
      </div>
    );
  }
}

export default Home;

这是列表组件:

import React from 'react';
import PropTypes from 'prop-types';

// prettier-ignore
const RecipeList = props => (

    <div style={props.style}>
      <h2 className="h2"> Recipes </h2>
      <ul className="list-reset">
        {props.recipes.map(recipe => (
          <li
            className="py2 border-bottom border-bottom-dashed pointer"
            key={recipe.id}
            onClick={() => props.onClick(recipe.id)}
          >
            <span
              className="mr1"
              onClick={e => {
                e.stopPropagation();
                props.onFavorited(recipe.id);
              }}
              role="img"
              aria-label="favorite"
            >
            {props.favorites.includes(recipe.id) ?  '✅' : ''}
            </span>
            <span>{recipe.name}</span>
            <span>{recipe.category}</span>
          </li>
        ))}
      </ul>
    </div>
  );

RecipeList.propTypes = {
  recipes: PropTypes.array,
  favorites: PropTypes.array,
  onClick: PropTypes.func,
  className: PropTypes.string,
  style: PropTypes.object,
};

RecipeList.defaultProps = {
  recipes: [],
  favorites: [],
};

export default RecipeList;

2 个答案:

答案 0 :(得分:1)

您正在将食谱ID添加到Error: Cannot enqueue Query after invoking quit. 数组,而不是具有class gDB { close() { return new Promise(function(resolve, reject) { db.end(function(error) { if ( error ){ reject(new Error(error)); } // For some reason it is necessary to reestablish this db = mysql.createConnection({ host: process.env.DBHOST, user: process.env.DBUSER, password: process.env.DBPASS, database: process.env.DBNAME, ssl: { ca: fs.readFileSync(__dirname + '/' + process.env.DBCA) } }); resolve(true); }); }); } getSnapshotIds(gId, uId) { return new Promise(function(resolve, reject) { var sql = 'SELECT id AS snapshotId FROM snapshots WHERE gId=' + db.escape(gId) + ' AND uId=' + db.escape(uId) + ' ORDER BY timestamp DESC'; db.query(sql, function (error, results, fields) { if (error) { db.destroy(); reject(new Error(error)); } else { resolve(results); } }); }); } getSnapshotFull(snapshotId) { return new Promise(function(resolve, reject) { var sql = 'SELECT s.id AS snapshotId, s.timestamp, s.gId, s.uId, s.clientId FROM snapshots s INNER JOIN controls c ON s.id = c.snapshotId INNER JOIN weathers w ON s.id = w.snapshotId WHERE s.id=' + db.escape(snapshotId); db.query(sql, function (error, results, fields) { if (error) { db.destroy(); reject(new Error(error)); } else { resolve(results[0]); } }); }); } getTs(snapshotId) { return new Promise(function(resolve, reject) { var sql = 'SELECT t.t, st.value FROM snapshots s LEFT JOIN snapshot_t st ON s.id = st.snapshotId INNER JOIN ts t ON st.tId = t.id WHERE s.id=' + db.escape(snapshotId); db.query(sql, function (error, results, fields) { if (error) { db.destroy(); reject(new Error(error)); } else { resolve(results); } }); }); } 属性的对象。

您只需要比较元素本身与在favorites方法中传入的id中即可。

id

答案 1 :(得分:0)

if (idx !== -1) { return { ...state, favorites: favorites.filter(f => f.id !== id) }; }

在这里遍历数组,使用过滤器检查带有f.id的对象是否与您要添加的id参数相同。那就好了。但是,在数组上添加新条目时,这是您正在做的事情:

{ ...state, favorites: [...favorites, id] };

您没有添加新对象,仅添加了ID。每当您尝试取消选中它时,它都会失败。

不知道要执行的操作的细节,但是我认为您应该在toggleFavorite函数中接受整个对象作为参数,然后执行相等性检查。

它看起来像这样:

toggleFavorite = recipe => {
    this.setState(({ favorites, ...state }) => {
      const idx = favorites.indexOf(recipe.id);
      if (idx !== -1) {
        return { ...state, favorites: favorites.filter(f => f.id !== recipe.id) };
      }
      return { ...state, favorites: [...favorites, recipe] };
    });
  };
  
  // In your list component...
  
  <span
    className="mr1"
    onClick={e => {
      e.stopPropagation();
      props.onFavorited(recipe.id);
    }}
    role="img"
    aria-label="favorite"
  >
    {props.favorites.find((f) => f.id === recipe.id) ?  '✅' : ''}
  </span>