Getting one object out of array

So, I dont think I have done this before in javascript. I have the two recipe names taco and pizza already showing in a list. If I click on say pizza then I want to display pizza’s name, ingredients, directions etc. If I click on tacos then the taco info should show up. Which I guess I should put eventlisteners on those li’s so I know they are clicked? This is more just learning and messing around before I attempt the actual project. im assuming I need the index of the array and compare that?

heres the code ive been messing with

class RecipeBox extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      editRecipe: '',
      addRecipe: '',
     recipes :
      [{
        name: "Tacos",
        directions: "make tacos",
        ingredients: ["meat"]
      },
      {
        name: "pizza",
        directions: "bake",
        ingredients: ["dough"]
      }]
    };
    
  
    this.handleAddSubmit = this.handleAddSubmit(this);
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  
  }///
  
  handleChange (evt) {
   
    this.setState({ [evt.target.name]: evt.target.value }.split(" "));
    
  }
  
  //submit for EditList
   handleSubmit() {
    const recipes = [...this.state.recipes];
    recipes[0].name = this.state.editRecipe;
    this.setState({
      recipes,
      editRecipe: ""
    });
  }
  
  handleAddSubmit(){
    const obj = {'name' : this.state.addRecipe};
    const recipes = [...this.state.recipes]
    recipes.push(obj);
    this.setState({
      recipes,
      addRecipe: ""
    })
    console.log(recipes);
  }
  
  render(){
   
    const ITEMS = this.state.recipes.map(({name}) => <li>{name}</li>)
                                         
    return(
      
      <div>
        
          <ul>                                                     
          {ITEMS}
          </ul>
                                          
          
          <EditList input = {this.state.editRecipe}
          handleChange = {this.handleChange}
          onSubmit = {this.handleSubmit}/>
                                           
          <AddRecipe input = {this.state.addRecipe}
          handleChange = {this.handleChange}
          onAddSubmit = {this.handleAddSubmit} />
        </div>
    )
  }
}

class EditList extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
     
    return(
      <div>
        <input type='text'
          value = {this.props.input}
          onChange = {this.props.handleChange}
          name="editRecipe"
         />
        <button onClick={this.props.onSubmit}>Edit</button>
       </div>
     )
  }
}

class AddRecipe extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
     
    return(
      <div>
        <input type='text'
          value = {this.props.input}
          onChange = {this.props.handleChange}
          name="addRecipe"
         />
        <button onClick={this.props.onAddSubmit}>Save</button>
       </div>
     )
  }
}
ReactDOM.render(<RecipeBox />, document.getElementById('app'));

Yes you need to add an event listener to reach li.

What you can do is create a method that sets the current recipe.

handleRecipeClick(index){
  this.setState({
  selectedRecipe: { ...this.state.recipes[index]}    // here you set a copy of the recipe as the selected recipe
});
}

Then you set this function in the event listener on each li

const ITEMS = this.state.recipes.map(({ name }, index) => 
  <li onClick={() => this.handleRecipeClick(index)> {name}</li>)

You can then render you selected recipe based on the state:

<ul>                                                     
          {ITEMS}
</ul>

<h2> Current Recipe </h2>
Name: {this.state.selectedRecipe.name}
Directions: {this.state.selectedRecipe.directions}
Ingredients: {this.state.selectedRecipe.ingredients.join(,)}

Another option is to give each recipe a unique id and then just store the id in the state as selectedId and render it using this.state.recipes.find(recipe => receipe.id === this.state.selecedId)

Sorry it took me so long to reply… took a break yesterday from all this. So I tried your code on codepen just to mess with it, and actually see what its doing. However I cant seem to get it to render, and theres no error in the code pen. I assumed that selectedRecipe was an empty object in state since it gets set to a recipe in the function

class RecipeBox extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
     selectedRecipe: {},
     recipes :
      [{
        name: "Tacos",
        directions: "make tacos",
        ingredients: ["meat"]
      },
      {
        name: "pizza",
        directions: "bake",
        ingredients: ["dough"]
      }]
    };
    this.handleRecipeClick = this.handleRecipeClick.bind(this);
  }

  handleRecipeClick(index){
  this.setState({
  selectedRecipe: { ...this.state.recipes[index]}    // here you set a copy of the recipe as the selected recipe
});
}



 render() {
   const ITEMS = this.state.recipes.map(({ name }, index) => 
  <li onClick={ this.handleRecipeClick(index)}> {name}</li>)
                                            
    return(
      <div>
         <ul> {ITEMS}</ul>
      </div>

This is what I have.

So, I am going to be 100% honest here. I am not to sure if I understand all that, and I dont want to use code that I do not understand if I was to be asked about it. I liked collin’s original suggestion, but after checking the code pen console im getting a object error somewhere. I do appreciate your willingness to help with those solutions

I caught that earlier, but I still have an error in the console for code pen. It is

[object error] {
framesToPop:1
name: "invariant violation"
}

I did some looking, and I think it may be the calling of state below the h2? The rest of my code worked before the addition of the new map, and the new rendering

Nevermind! made my own mistake not pay attention to what I was doing. Appreciate the suggestions, and sticking with me

1 Like