2017-07-29 24 views
0

我正在处理我的第一个React应用程序。这是一个应用程序的配方。它有一个成分过滤器。主要组件是Cookbook组件。它有一个Filter组件和一个Recipe组件。如何使用React管理复选框筛选?

配方组件显示加载时的所有配方。 Filter组件显示所有需要的成分或订书钉。这部分都很好。

我现在想要做的是当一个人点击一个主食时,让我们说黄油,然后过滤整个食谱列表。我的假设是我需要通过Filter的状态。我怎样才能用这些复选框来做到这一点?

以下是我有:

import React from 'react'; 
import ReactDOM from 'react-dom'; 
import './index.css'; 
var data = require('./recipes.json'); 

function IngredientDetailList(props){ 
    const ingredientList = props.ingredientList; 
    const listItems = ingredientList.map((ingredient, index) => 
     <div key={index}> 
      {ingredient.measurement_amount}&nbsp; 
      {ingredient.measurement_unit}&nbsp; 
      {ingredient.ingredient} 
     </div> 

    ); 
    return (
     <div>{listItems}</div> 
    ) 
} 


function Recipe(props){ 
    const recipeList = props.cookbook.recipes 
    const listItems = recipeList.map((recipe) => 
     <div key={recipe.id}> 
      <h2>{recipe.name}</h2> 
      <IngredientDetailList ingredientList = {recipe.ingredient_list}/> 
     </div> 

    ); 
    return(

     <div>{listItems}</div> 
    ) 
} 

class Filter extends React.Component { 
    constructor(){ 
     super(); 
     this.state = { 
      checkedStaples: {}, 
     } 
    } 

    render(){ 
     const stapleList = this.props.stapleList; 
     const checkboxItems = stapleList.map((staple, index) => 
      <div key = {index}> 
      <label> 
       <input type="checkbox" value="{staple}"/> 
       {staple} 
      </label> 
      </div> 
     ); 
     return (
      <form> 
       {checkboxItems} 
      </form> 
     ); 
    } 
} 


class Cookbook extends React.Component { 
    constructor(){ 
     super(); 
     this.state ={ 
      cookbook: data 
     } 
    } 

    getStapleList(recipes){ 
     let stapleList = []; 
     recipes.forEach(function(recipe){ 
      recipe.ingredient_list.forEach(function(list){ 
       stapleList.push(list.needed_staple); 
      }); 
     }); 

     let flattenedStapleList = stapleList.reduce(function(a,b){ 
      return a.concat(b); 
     }) 

     return flattenedStapleList 
    } 

    render(){ 
     const cookbook = this.state.cookbook; 
     const stapleList = this.getStapleList(cookbook.recipes); 
     return(
      <div className="cookbook"> 
       <div className="filter-section"> 
        <h1>This is the filter section</h1> 
        <Filter stapleList = {stapleList}/> 
       </div> 
       <div className="recipes"> 
        <h1>This is where the recipes go</h1> 
        <div className="recipe">  
         <Recipe cookbook = {cookbook}/> 
        </div> 
       </div> 
      </div> 
     ); 
    } 
} 

ReactDOM.render(
    <Cookbook />, 
    document.getElementById('root') 
); 

回答

1

你可以尝试做这样的事情:

// .... 

function Recipe(props){ 
    const selectedStaples = props.selectedStaples; 
    const recipeList = props.cookbook.recipes 

    const listItems = recipeList.map((recipe) => { 
     const hasStaple = ingredient_list.reduce(
      (_hasStaple, staple) => _hasStaple || selectedStaples.includes(staple), 
      false 
     ); 

     // only show recipe if it has a staple 
     if (selectedStaples.length === 0 || hasStaple) 
      return (
       <div key={recipe.id}> 
        <h2>{recipe.name}</h2> 
        <IngredientDetailList ingredientList = {recipe.ingredient_list}/> 
       </div> 
      ); 
     } 

     return null; 
    } 

    ); 
    return(

     <div>{listItems}</div> 
    ) 
} 

class Filter extends React.Component { 
    constructor(){ 
     super(); 
     this.state = { 
      checkedStaples: {}, 
     } 
    } 

    render(){ 
     const stapleList = this.props.stapleList; 
     const checkboxItems = stapleList.map((staple, index) => 
      <div key = {index}> 
      <label> 
       <input 
        type="checkbox" 
        value="{staple}" 
        onClick={e => this.props.onChange(staple, e.checked)} 
       /> 
       {staple} 
      </label> 
      </div> 
     ); 
     return (
      <form> 
       {checkboxItems} 
      </form> 
     ); 
    } 
} 


class Cookbook extends React.Component { 
    constructor(){ 
     super(); 
     this.state ={ 
      cookbook: data, 
      selectedStaples: [] 
     } 
    } 

    getStapleList(recipes){ 
     let stapleList = []; 
     recipes.forEach(function(recipe){ 
      recipe.ingredient_list.forEach(function(list){ 
       stapleList.push(list.needed_staple); 
      }); 
     }); 

     let flattenedStapleList = stapleList.reduce(function(a,b){ 
      return a.concat(b); 
     }) 

     return flattenedStapleList 
    } 

    handleOnChange(staple, isChecked) { 
     const selectedStaples = this.state.selectedStaples; 
     if (isChecked) { 
      this.setState({ 
       selectedStaples: selectedStaples.push(staple); 
      }) 
     } else { 
      this.setState({ 
       selectedStaples: selectedStaples.filter(selectedStaple => selectedStaple !== staple); 
      }) 
     } 
    } 

    render(){ 
     const selectedStaples = this.state.selectedStaples; 
     const cookbook = this.state.cookbook; 
     const stapleList = this.getStapleList(cookbook.recipes); 
     return(
      <div className="cookbook"> 
       <div className="filter-section"> 
        <h1>This is the filter section</h1> 
        <Filter stapleList = {stapleList} onChange={this.handleOnChange.bind(this)}/> 
       </div> 
       <div className="recipes"> 
        <h1>This is where the recipes go</h1> 
        <div className="recipe">  
         <Recipe cookbook = {cookbook} selectedStaples={selectedStaples} /> 
        </div> 
       </div> 
      </div> 
     ); 
    } 
} 

ReactDOM.render(
    <Cookbook />, 
    document.getElementById('root') 
); 

它跟踪的食谱组件中选定镫骨并传递到食谱

+0

所以,我加了这个,并调整它使其工作。谢谢您的帮助!我看到的一个问题是,我似乎无法完成handleOnChange工作......特别是,this.state.selectedStaples不断地以未定义的方式进行轰炸。我目前的猜测是,它没有看到Filter中的参数,为此我试图传递状态......仍然没有运气。我将添加我的更新到编辑...任何想法? – notthehoff

+0

啊啊,原因是因为你使用了一个es6类的组件,该方法不会自动绑定到'this'。你可以将'onChange = {this.handleOnChange}'改成'onChange = {()=> this.handleOnChange()}'或'onChange = {this.handleOnChange.bind(this)}' – alecrobins