onClick trigger on single div React

I am firing onClick event when a button is clicked. when it gets clicked the div appears and reappears. however, the problem i am facing is if i click a button on particular div , all of the div appears instead of the div I clicked button on. How can i make it work that a particular div appears on which the button was clicked.

const single_recipe = props => {
    const [show,setShow] = useState(false);

    

    return(
        <Auxiliary>
            <div className={classes.Single_recipe}>
                <img className={classes.Recipe_img} src={props.img} alt={props.recipeName}/>
                <h2 className={classes.Recipe_name}>{props.recipeName}</h2>
                <div className={classes.ButtonBox}><button className={classes.GetRecipebtn} 
                onClick={() => setShow(!show)}>Ingredients</button>
                </div>
                
                {show && <Ingredients ingredients={props.ingredients}/> }
                    
               
            </div>
            
        </Auxiliary>
    )
}

Can you elaborate a bit? What do you mean by

“all of the div appears instead of the div I clicked a button on”

In the code, the Ingredients component looks like it should be conditionally rendered based on the show state. Is more than one div appearing? Do you re-use this component anywhere else?

We need more context and code I think.

I don’t believe I see a reason why each version of the component shouldn’t have its own state. I assume it’s being mapped in the parent?


You should really uppercase your component name, I’m also curious what Auxiliary is? React has fragments <></> if that is what it is used for (which the name might imply).

1 Like


Uploading: Screenshot 2021-11-27 at 17.46.26.png…

when i click on the ingredients of a particular recipe all other recipe ingredients collapses. I am not calling Ingredients component anywhere else.

Images are not going to let us know what is going on in the code. Please link to a GitHub repo or a live example on something like CodeSandbox.

I have edited my post
App.js Component

class App extends Component {
  state = {
    searchInput: '',
    data: [],
    error: false,
    isLoading: false,
    isShow: false,
  };

  onChangeHandler = (event) => {
    this.setState({ searchInput: event.target.value });
  };

  onSubmitHandler = (event) => {
    event.preventDefault();
    let searchTerm = this.state.searchInput;
    console.log(this.state.searchInput);
    this.searchRecipe(searchTerm);
    this.setState({ searchInput: '' });
  };

  searchRecipe = (searchTerm) => {
    this.setState({ error: false });

    if (searchTerm) {
      axios
        .get(
          `https://api.edamam.com/search?q=${searchTerm}&app_id=${API_ID}&app_key=${API_KEY}`
        )
        .then((responseData) => {
          console.log(responseData);
          this.setState({ data: responseData.data.hits });

          console.log(this.state.data);
        })
        .catch((err) => console.log(err));
    } else {
      this.setState({ error: true });
    }
  };

  render() {
    let recipes = this.state.data;

    const inputClasses = [classes.InputText];
    if (this.state.error) {
      inputClasses.push(classes.Invalid);
    }

    return (
      <div className="App">
        <Navbar />
        <form className={classes.FormElement} onSubmit={this.onSubmitHandler}>
          <input
            className={inputClasses.join(' ')}
            type="text"
            placeholder="Search for recipe..."
            onChange={this.onChangeHandler}
            value={this.state.searchInput}
          />
          <button className={classes.InputButton} type="submit">
            <FaSearch style={{ fontSize: '22px' }} />
          </button>
        </form>
        {this.state.error ? (
          <p className={classes.ErrorMessage}>Please enter a search query</p>
        ) : (
          <div className={classes.Recipes}>
            {recipes.length > 0 &&
              recipes.map((recipe) => {
                return (
                  <Single_recipe
                    key={uuidv4()}
                    img={recipe.recipe.image}
                    recipeName={recipe.recipe.label}
                    ingredients={recipe.recipe.ingredients}
                  />
                );
              })}
          </div>
        )}
      </div>
    );
  }
}

export default App;

Single_recipe.js Component

const single_recipe = (props) => {
  const [show, setShow] = useState(false);

  return (
    <Auxiliary>
      <div className={classes.Single_recipe}>
        <img
          className={classes.Recipe_img}
          src={props.img}
          alt={props.recipeName}
        />
        <h2 className={classes.Recipe_name}>{props.recipeName}</h2>
        <div className={classes.ButtonBox}>
          <button
            className={classes.GetRecipebtn}
            onClick={() => setShow(!show)}
          >
            Ingredients
          </button>
        </div>

        {show && (
          <Modal>
            <Ingredients ingredients={props.ingredients} />{' '}
          </Modal>
        )}
      </div>
    </Auxiliary>
  );
};

export default single_recipe;

Ingredient.js Component

const ingredients = (props) => {
  return props.ingredients.map((ing) => {
    return (
      <ul className={classes.Ingredients} key={uuidv4()}>
        <li className={classes.Individual_ingredient}>{ing.text}</li>
        <li className={classes.Individual_ingredient}>weight- {ing.weight}</li>
      </ul>
    );
  });
};

export default ingredients;

Please edit your post and reformat the code.


When you enter a code block into a forum post, please precede it with a separate line of three backticks and follow it with a separate line of three backticks to make it easier to read.

You can also use the “preformatted text” tool in the editor (</>) to add backticks around text.

See this post to find the backtick on your keyboard.
Note: Backticks (`) are not single quotes (’).

I edited your post and formatted the code.

Next time instead of trying to edit what you have already posted it would be easier if you just pasted your code in again using the correct code formatting syntax.


Still not sure I see what the problem is. Where is the <Modal> component coming from? What does it do and how is it controlled?

The problem is when I click on a p[articular recipe ingredient all other recipe ingredients also appears or the card collapses. I haven’t created the Modal component yet.

Now I’m honestly not sure what you are saying the problem is.

Is it clicking the button to show/hide the Ingredients component that isn’t working, or is it clicking the ul that it is returning that is causing an issue?

Anyway, if you create a live version on CodeSandbox we can at least test the code.

when clicking the button to show/hide for a particularly recipe ingredient that causes the iNGREDIENT component to render instead it gets rendered for all the recipes.

So does every recipe component have its own ingredient component? And if that’s the case, do they all use the same exact show state in order to conditionally render themselves?

Making a version on codesandbox would allow us to see and toy with the code. For the time being, I can only make assumptions.

As said, we really need to see it live or at least have all the code from a working version we can test. So a repo or a CodeSandbox.

I’m not seeing the behavior you are talking about. Here is an example using your code with a mock response (no search code). I did rename a few things but other than that is should be about the same. As said, each SingleRecipe component has its own state and is working as expected.

Thanks for reply. This is the link to codesandbox adoring-cherry-n46zs - CodeSandbox

I don’t see the problem in your CodeSandbox either.

I’m starting to think you just haven’t explained the problem and looking at the images you posted I also don’t see the problem as explained and asked about.

Is this a CSS problem? Are you just talking about the height of the cards all expanding when opening the recipe in one of the cards? Because the .Recipes container will be as tall as the tallest child element, which would be the card with the recipe details open. There is nothing odd about that. Not that it is how you would want it to look but it isn’t a React or code problem, but a layout issue with CSS.

The height of other cards are also expanding when I click on particular card.

This isn’t a code issue at all, just CSS.

They are flex items, that’s how it works. You need to learn about flexbox and layouts. You can compare it to an inline-block version to better see what I mean (not suggesting you use it).

.Recipes {
 /* just a leftover from the old CSS you won't want this either
  a positive value might make sense
*/
  margin-top: -80px;
}

.Single_recipe {
  display: inline-block;
  width: 25%;
  vertical-align: top;
  box-sizing: border-box;
  margin: 25px;
  border: 1px solid #ccc;
  border-radius: 5px;
  box-shadow: 0 5px 5px 0 #aaa;
  transition: all 0.5s cubic-bezier(0.39, 0.575, 0.565, 1);
}

CodeSandbox inline-block example


BTW, you still need to rename the single_recipe component.

React Hook “useState” is called in function “single_recipe” that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. (react-hooks/rules-of-hooks) eslint