显示/hide(sub)列出了带有react JS的项目



在React JS组件中,我正在使用来自App Parent的组件传递的数组中的JS MAP函数呈现项目列表(配方)。每个项目都有一个子列表(成分),再次使用地图功能渲染。

我想要的是在单击食谱标题时显示/隐藏成分的子列表。我在标题上使用on Click函数,该函数将CSS设置为无或封锁,但是我会收到以下错误:

uck offult typeError:无法读取未定义的

的属性'OpenRecipe'

这是我的代码:

var App = React.createClass({

  getInitialState(){
    return{
      showModal:false,

      recipeKeys: [ ],
      recipes: [ ]
    }

  },
  addRecipeKey: function(recipe){

    var allKeys = this.state.recipeKeys.slice();
    var allRecipes = this.state.recipes.slice();
    allKeys.push(recipe.name);
    allRecipes.push(recipe);
    localStorage.setObj("recipeKeys", allKeys);

    this.setState({recipeKeys: allKeys, recipes: allRecipes}, function(){
      console.log(this.state);

    });

  },
  componentDidMount: function(){
    var dummyRecipes = [
      {
        "name": "Pizza",
        "ingredients": ["Dough", "Tomato", "Cheese"]
      },
      {
        "name": "Sushi",
        "ingredients": ["Rice", "Seaweed", "Tuna"]
      }
    ]

    if(localStorage.getItem("recipeKeys") === null){
        localStorage.setObj("recipeKeys", ["Pizza", "Sushi"]);
        dummyRecipes.forEach(function(item){
        localStorage.setObj(item.name, item);  
        });    
        this.setState({recipeKeys: ["Pizza", "Sushi"], recipes: dummyRecipes}, function(){
          console.log(this.state);
        });

    } else {
      var recipeKeys = localStorage.getObj("recipeKeys");
      var recipes = [];
      recipeKeys.forEach(function(item){
        var recipeObject = localStorage.getObj(item);
        recipes.push(recipeObject);
     });

     this.setState({recipeKeys: recipeKeys, recipes: recipes}, function(){
       console.log(this.state);
     });

    }

  }, 

  open: function(){

    this.setState({showModal:true});
  },
    close: function(){

    this.setState({showModal:false});
  },
  render: function(){
    return( 
      <div className="container">
        <h1>Recipe Box</h1>
        <RecipeList recipes = {this.state.recipes} />
        <AddRecipeButton openModal = {this.open}/>
        <AddRecipe closeModal = {this.close} showModal={this.state.showModal} addRecipeKey = {this.addRecipeKey}/>
      </div>
    )  
  }

});
var RecipeList = React.createClass({

  openRecipe: function(item){

    var listItem = document.getElementById(item);
    if(listItem.style.display == "none"){
        listItem.style.display = "block";
    } else {
      listItem.style.display = "none";      
    }    
   },
  render: function(){    
   return (
      <ul className="list-group">
        {this.props.recipes.map(
          function(item,index){
            return (
              <li className="list-group-item" onClick={this.openRecipe(item)}> 
                <h4>{item.name}</h4>
                <h5 className="text-center">Ingredients</h5>
                <hr/>
                <ul className="list-group" id={index} >
                {item.ingredients.map(function(item){
                  return (
                    <li className="list-group-item">  
                    <p>{item}</p>
                     </li>  
                  )
                })} 
                </ul>  
              </li>  
            )
          }

        )

        }
      </ul>  

    ) 

  } 

});
ReactDOM.render(<App />, document.getElementById('app'));

另外,我在这里尝试使用CSS方法,但是也许有一种更好的方法可以使用React?

有人可以帮我吗?谢谢!

您的问题是您在地图中失去了此上下文...您需要将.bind(this)添加到地图功能的末尾

{this.props.recipes.map(function(item,index){...}.bind(this))};

我回答了另一个与此相似的问题。如果您可以使用箭头功能,则它会自动绑定为您绑定最好的。如果您不能这样做,那么要么使用绑定或使您在地图功能中使用的上下文的阴影变量。

现在进行清理部分。您需要稍微清理代码。

var RecipeList = React.createClass({
  getInitialState: function() {
    return {display: []};
  },
  toggleRecipie: function(index){
    var inArray = this.state.display.indexOf(index) !== -1;
    var newState = [];
    if (inArray) { // hiding an item
        newState = this.state.display.filter(function(item){return item !== index});
    } else { // displaying an item
        newState = newState.concat(this.state.display, [index]);
    }
    this.setState({display: newState});
  },
  render: function(){
   return (
      <ul className="list-group">
        {this.props.recipes.map(function(item,index){
            var inArray = this.state.display.indexOf(index) !== -1;
            return (
              <li className="list-group-item" onClick={this.toggleRecipie.bind(this, index)}> 
                <h4>{item.name}</h4>
                <h5 className="text-center">Ingredients</h5>
                <hr/>
                <ul className="list-group" id={index} style={{display: inArray  ? 'block' : 'none'}} >
                {item.ingredients.map(function(item){
                  return (
                    <li className="list-group-item">  
                    <p>{item}</p>
                     </li>  
                  )
                }.bind(this))} 
                </ul>  
              </li>  
            )
          }.bind(this))
        }
      </ul>  
    ) 
  } 
});

这可能有些复杂,您可能不想管理指示要切换成分视图的列表。我建议您为代码制作组件,这样它就更为反应,并且使切换视图更加容易。

我也将在ES6语法中写下这一点,就像您应该使用ES6一样。

const RecipieList = (props) => {
    return (
        <ul className="list-group">
            {props.recipes.map( (item,index) => <RecipieItem recipie={item} /> )
        </ul>  
    );
};
class RecipieItem extends React.Component {
    constructor(){
        super();
        this.state = {displayIngredients: false}
    }
    toggleRecipie = () => {
        this.setState({displayIngredients: !this.state.displayIngredients});
    }
    render() {
        return (
            <li className="list-group-item" onClick={this.toggleRecipie}> 
                <h4>{item.name}</h4>
                <h5 className="text-center">Ingredients</h5>
                <hr/>
                <ul className="list-group" style={{display: this.state.displayIngredients  ? 'block' : 'none'}} >
                    {this.props.recipie.ingredients.map( (item) => <IngredientItem ingredient={item} /> )} 
                </ul>  
            </li>
        );
    }
}
const IngredientItem = (props) => {
    return (
        <li className="list-group-item">  
            <p>{props.ingredient}</p>
        </li>
    );
};

您也可以使用类似的东西:

  render: function(){    
   var self = this;
   return (
      <ul className="list-group">
        {this.props.recipes.map(
          function(item,index){
            return (
              <li className="list-group-item" onClick={self.openRecipe(item)}>.....

最新更新