jcs1977
jcs1977

Reputation: 245

How to pass a prop back from child to parent in onclick handler and then to another component in React?

I am passing a function to a grandchild (SingleProject) from my parent (App) that opens a model. The grandchild just renders an li in the child (Gallery) that show a list of images(coming from the grandchild). I am trying to get the object from props on the grandchild, pass it back to App, and then through to the modal (Modal) to display the information about the image. The objects that hold the info about the images are stored in a service (module.exports). The openModal function is what is being passed along to the grandchild. The closeModal will be passed to the modal. I am having problems with this. Any help would be appreciated.

//APP (Parent)

class App extends Component {
constructor(props) {
super(props);

this.closeModal = this.closeModal.bind(this);
this.openModal = this.openModal.bind(this);

this.state = {
  open: false,
  projects: Service,
  selectedProject: Service[0]
}

    console.log('selectedProject: ', this.state.selectedProject)
}

closeModal(event) {
this.setState({open: false});
console.log('app: ', this.state.open);
}

openModal(event) {
this.setState({open: true});
console.log('app: ', this.state.open);
}

render() {
const show = {
  display: 'block'
};

const hide = {
  display: 'none'
};
return (
  <div>
    <div             style={this.state.open === false ? hide : show}>
      <Modal
        value={this.state.open}
        closeModal={this.closeModal}
        project={this.state.selectedProject}
      />
    </div>
    <Header />
    <Intro />
    <WhatIDo />
    <WhoIAm />
    <Gallery
      value={this.state.open}
      projects={this.state.projects}
      openModal={this.openModal}
    />
    <Contact />
    <Footer />
  </div>
 );
}
}

//GALLERY (child)

const Gallery = (props) => {
console.log('props: ', props)
const projectItems = props.projects.map(project => {
return (
  <SingleProject
    key={project.name}
    project={project}
    openModal={props.openModal}
  />
);
});

return (
<div className="gallery">
  <h3>My Work</h3>
  <ul>{projectItems}</ul>
</div>
);
}

//SINGLEPROJECT (grandchild)

const SingleProject = (props) => {
return (
<li className="gallery-images">
  <img
    src={props.project.img}
    onClick={props.openModal}
  />
</li>
);
}

//MODAL (Modal)

const Modal = (props) => {
return(
<div className="modal">
  <div
    className="modal-close"
    onClick={props.closeModal}
  />
  <ModalDesc project={props.project} />
</div>
);
}

//SERVICE

module.exports = [
{
name: 'xxx',
img: '.././images/gallery/xxx',
link: 'xxx',
tech: 'AngularJS, jQuery, HTML, CSS, PostgreSQL, Node.js, Gulp, Express.js',
desc: 'A clone of the Texas restaurant Dixie Chicken\'s website featuring a 
backend and some parallax effects. This site is not fully responsive.'
},
{
name: 'xxx',
img: '.././images/gallery/xx',
link: 'xxx',
tech: 'AngularJS, jQuery, HTML, CSS, PostgreSQL, Node.js, Gulp, Express.js',
desc: 'A fully responsive clone of the E-commerce website Stance. This was a 
group project. I did the set up of the backend, the endpoints, the frontend 
state management, the directives, most of the SQL files, the single products 
view, the login view, the account view, and the register view.'
},
{
name: 'xxx',
img: '.././images/gallery/xxx',
link: 'xxx',
tech: 'AngularJS, jQuery, HTML, CSS',
desc: 'A fully responsive site for The Battlefield Pilot Club.'
}
];

Upvotes: 2

Views: 515

Answers (1)

Raghudevan Shankar
Raghudevan Shankar

Reputation: 1093

If I understand what you need correctly, you want to pass the project information to the openModal method

You just have to make a small edit to the SingleProject component

const SingleProject = (props) => {
  return (
    <li className="gallery-images">
      <img
       src={props.project.img}
       onClick={() => props.openModal(props.project)}
      />
   </li>
  );
}

and then in your openModal method you can set the selectedProject;

openModal(project) {
  this.setState({
    open: true,
    selectedProject: project,
  }, () => {
    console.log('app: ', this.state.open); // this will print "true"
  });
  console.log('app: ', this.state.open); // this will print "false"
}

Explanation:

  1. Instead of passing props.onClick to the onClick prop of <img/> we wrap it with an arrow function that will invoke props.onClick with the project object
  2. When you're logging the state in the openModal method, if you want it to print true you'll need to print it in the callback to the setState method since the setState call does not immediately set the state of the class but rather, react will batch the updates. official documentation for the same here

Upvotes: 1

Related Questions