2017-07-29 70 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