1

I am new to react, so please be patient if I seem to not understand some obvious concept, but I wrote a profile-log function with the profiles structured like this :

{id:1, name: John Smith, age: 27, height: 186cm, Gender: male}

I am designing a react function (for learning purposes), That sorts, adds, deletes, and modifies the profiles.

To edit the profiles I am using hooks. I then use the hook functions as props inside the components.

I call a "Header" function that uses a "PrintOut" function which displays every profile on the DOM along with a delete, edit, and Change gender button.

it also takes in 3 props, the profile state, delete function, and toggle (gender-change) function. The gender-change function is initiated on a click and for now, all it is suppose to do is just console log 'You clicked gender change function' along with the ID.

instead of doing that, the console just logs that sentence for each profile without a click. And when I do click the "change gender" button, nothing happens.

I would like to know why this is the case and what can I do to fix it?

here is the code

App.js

import "./styles.css";
import Header from "./component/Header";
import Buttons from "./component/Buttons";
import { useState } from "react";
 
export default function App() {
 const [names, assortNames] = useState([
   {
     id: 1,
     name: "John",
     age: 18,
     height: 184,
     gender: "male"
   },
   {
     id: 2,
     name: "Billy",
     age: 24,
     height: 191,
     gender: "male"
   },
   {
     id: 3,
     name: "Sara",
     age: 26,
     height: 171,
     gender: "female"
   },
   {
     id: 4,
     name: "Ryan",
     height: 186,
     age: 27,
     gender: "male"
   }
 ]);
 
 const AgeFilter = () => {
   assortNames(
     [...names].sort((a, b) => {
       return b.age - a.age;
     })
   );
 };
 
 const nameFilter = () => {
   assortNames([...names].sort((a, b) => a.name.localeCompare(b.name)));
 };
 const heightFilter = () => {
   assortNames(
     [...names].sort((a, b) => {
       return b.height - a.height;
     })
   );
 };
 
 const DeleteName = (id) => {
   assortNames(names.filter((names) => names.id !== id));
 };
 
 const GenderChange = (id) => {


 console.log('You clicked gender change function', id)
 };
 
 return (
   <div className="container">
     <Buttons
       list={names}
       Age={AgeFilter}
       Name={nameFilter}
       Height={heightFilter}
     />
     <Header namez={names} functs={DeleteName} Toggler={GenderChange} />
   </div>
 );
}

Header.js

import PrintOut from "./PrintOut";
 
const Header = ({ namez, functs, Toggler }) => {
 return (
   <>
     {namez.map((name) => (
       <PrintOut key={namez.id} name={name} onDelete={functs} onToggle ={Toggler} />
     ))}
   </>
 );
};
 
export default Header;

PrintOut.js

const PrintOut = ({ name, onDelete, onToggle }) => {
  const Deleter = (id) => {
    onDelete(name.id);
  };

  return (
    <div className={name.gender === "male" ? "male" : "female"} key={name.id}>
      <h3>{name.name}</h3>
      <div className="Age-and-Height">
        <p> {name.age}</p>

        <h4> {name.height} cm</h4>
      </div>
      <button className="btn btn-delete" onClick={() => Deleter(name.id)}>
        Delete
      </button>
      <button className="btn btn-edit">Edit</button>
      <button className="btn " onClick={onToggle(name.id)}>
        Change Gender
      </button>
    </div>
  );
};

export default PrintOut;

Buttons.js

const Buttons = ({ list, Age, Name, Height }) => {
  return (
    <>
      <div className="buttons">
        <button className="btn" onClick={Age}>
          AgeSort
        </button>
        <button className="btn" onClick ={Height}>HeightSort</button>
        <button className="btn" onClick ={Name}>NameSort</button>
        <button className="btn btn-add" >Add</button>
      </div>
    </>
  );
 };
  
 export default Buttons;
  • 1
    `onToggle(name.id)` is calling your function and putting the return of that function (undefined) as the value of your `onClick` prop, use `onClick={() => onToggle(name.id)}` – Nick Parsons Aug 22 '21 at 11:19

2 Answers2

1

Here you are directly invoking the function at the time it gets rendered:

<button className="btn " onClick={onToggle(name.id)}>
    Change Gender
</button>

So you need to change it to a callback function:

<button className="btn " onClick={() => onToggle(id)}>
     Change Gender
</button>

Also putting id to your child component

Ryan Le
  • 7,708
  • 1
  • 13
  • 23
  • I thought the onClick even-listener was there to prevent a direct invoke? is there a circumstance where it would make sense to have the onClick event-Listener and directly invoke it? – Maxwell Derry Aug 22 '21 at 11:22
  • Every time you call a function with `()` will invoke itself. OnClick receives a function, while you invoke it got the result of that function. – Ryan Le Aug 22 '21 at 11:24
  • "Also putting id to your child component", you mean the button component? – Maxwell Derry Aug 22 '21 at 11:26
  • It's the `PrintOut` component which you put name.id there. – Ryan Le Aug 22 '21 at 11:28
0

You are not passing the id the that function

Toggler={() => GenderChange(id)}
Nitsan Cohen
  • 619
  • 3
  • 6