当前位置: 首页 > 知识库问答 >
问题:

使用React JS显示/隐藏(子)列表项

秦鹏飞
2023-03-14

在React JS组件中,我正在渲染一个项目列表(食谱),使用来自数组的JS映射函数,从应用程序父组件传入。每个项目都有一个子列表(配料),同样使用地图功能呈现。

我想要的是,当你点击菜谱标题时,显示/隐藏配料的子列表。我在标题上使用了onClick函数,将CSS设置为显示none或block,但出现以下错误:

无法读取未定义的属性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?

有人能帮我吗?谢谢

共有2个答案

蓟雪峰
2023-03-14

您还可以使用类似以下内容:

  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)}>.....
平航
2023-03-14

您的问题是您正在地图中丢失此上下文。。。您需要将.bind(this)添加到map函数的末尾

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

我在这里回答了另一个非常类似的问题。如果您可以使用箭头函数,它会自动绑定,这是最好的。如果您不能做到这一点,那么可以使用一个bind,或者为您在map函数中使用的this上下文创建一个shadow变量。

现在是清理部分。你需要稍微整理一下你的代码。

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>
    );
};
 类似资料:
  • 问题内容: 我想显示一个带有控件的基本html表,以切换其他列的显示/隐藏: 因此,默认情况下,列1和列2将是唯一显示的列-但是,当您单击列1时,我希望1a和1b切换,与列2和2a和2b相同。我可能最终会有更多的列和很多行- 因此,当我进行测试时,任何JavaScript循环方法都太慢而无法使用。 似乎足够快的唯一方法是设置一些CSS,如下所示: 然后在表标题单元格上设置onClick函数调用,这

  • 问题内容: 我们现在在使用React时遇到了一些问题,但这 有点 归结于我们如何使用React的一部分。 我们应该如何显示/隐藏子组件? 这就是我们的编码方式(这只是组件的片段)… 最近,我一直在阅读一些示例,例如应该沿着以下方向进行: 我应该一直在使用那个React.render()吗?似乎停止了各种各样的事情,如级联到孩子和诸如… 问题答案: 我提供了一个工作示例,它遵循您的第二种方法。更新组

  • 问题内容: 我有一个包含几列的HTML表,我需要使用jquery实现一个列选择器。当用户单击复选框时,我要隐藏/显示表中的相应列。我想在不将类附加到表中的每个td的情况下执行此操作,是否可以使用jquery选择整个列?以下是HTML的示例。 问题答案: 我想做到这一点而不必在每个td上附加一个类 就个人而言,我会采用“每课时听课/课时/上课”的方法。然后,您可以通过对容器上的className的一

  • 我有一个桌子,它的膨胀和折叠,但它变得太乱,无法使用它,IE和Firefox不能正常工作。 下面是JavaScript代码: 和示例HTML: 问题是,我对每一个都使用一个ID,这是非常烦人的,因为我想为每个父级和很多父级都有很多隐藏行,所以要处理的ID太多了。IE和FireFox只显示第一个隐藏行,而不显示其他行。我怀疑发生这种情况是因为我将所有ID触发在一起使其工作。我认为如果我使用类而不是I

  • 问题内容: 我一直在寻找一个很好的技巧,使隐藏/显示内容或仅具有CSS而没有javascript的列表。我已成功执行此操作: 并且它正在工作,但没有达到应有的效果。这是问题所在:显示内容时,您可以通过单击“页面上的任何位置”将其隐藏。如何禁用它?如何通过单击“隐藏”隐藏内容“仅”?先感谢您! 问题答案: 我不会使用复选框,而是使用您已经拥有的代码 CSS HTML 这样,仅在单击hide元素时隐藏

  • 问题内容: 对于我正在做的网站,我想加载一个div,然后隐藏另一个,然后有两个按钮可以使用JavaScript在div之间切换视图。 这是我当前的代码 替换div2的第二个功能不起作用,但第一个功能起作用。 问题答案: 如何显示或隐藏元素: 为了显示或隐藏元素,请操纵元素的style属性。在大多数情况下,您可能只想更改元素的属性: 或者,如果您仍然希望元素占用空间(例如,如果您要隐藏表格单元格),