4

After doing some tutorials and reading the documentation, I'm trying to setup my first react project to try and get a real understanding of how it all works. So I'm a real beginner at this, And I have a feeling I'm not grasping a fundamental concept.

I'm having an issue trying to pass an object from a child component to it's parent. I've managed to pass the object to the parent, but can't then write it to the parent's state.

I may well be approaching this in completely the wrong way. any guidance would be apricated.

I've updated my code to now use a ref to pass the object to the parent However, I assuming because the refs are only processes by React after the HTML is rendered its allways passing back the last item in my object array not the one i want to associate with each selection.

class AppContainer extends React.Component { //parent Component
  constructor() {
    super();

    this.state = {
      contactsList:
        [
          {id:1, name: 'Tom Brace', phone: '0123456789', address:'fg dfgh dfgh dfgh dfgh', notes: 'sdfdsfasdfasdf asdf as df asdf  sadf a sdfasdf', Quote:''},

         ...

          {id:7, name: 'Dave Johnson', phone: '0123456789', address:'fg dfgh dfgh dfgh dfg', notes: 'sdfdsfasdfasdf asdf as df asdf  sadf a sdfasdf', Quote:''}
        ],
        selectedContact: {id:1, name: 'Tom Brace', phone: '0123456789', address:'fg dfgh dfgh dfgh dfg', notes: 'sdfdsfasdfasdf asdf as df asdf  sadf a sdfasdf', Quote:''}
    }
  }

  render(){
    return(
      <div className="container-fluid">
        <div className="row">
          <div id="sidebar" className="col-xs-12 col-md-3 sidebar">
             <ContactNav updateContact={this._updateContact.bind(this)}
                          contactsList={this.state.contactsList}
                        />
                      </div>
                      <div id="content" className="col-xs-12 col-md-9 main">
                        <Content
                          selectedContact={this.state.selectedContact}
                        />
                      </div>
                    </div>
                  </div>
                );
              };

              _updateContact(obj){
  console.log(obj)
                this.setState({
                selectedContact: obj
              });
              }
            }

            class ContactNav extends React.Component { //child of AppContainer

              render() {
                const contacts = this._getContacts() || [];
                return(
                  <div>
                    <div className="input-group">
                      <input type="text" className="form-control" placeholder="Search for..." />
                      <span className="input-group-btn">
                        <button className="btn btn-default" type="button">Go!</button>
                      </span>
                    </div>
                    <ul className="nav nav-sidebar">
                      {contacts}
                    </ul>
                  </div>
                );
              }
              _handleClick(){
                event.preventDefault();
console.log(this._obj);
                let obj = this._obj
                this.props.updateContact(obj);
              }


              _getContacts() {
                return this.props.contactsList.map((i) => {
                  return (
                    <li key={i.id}>
                      <a href="#" key={i.id} onClick={this._handleClick.bind(this)} ref={(input) => this._obj = i}>
                        {i.name}
                      </a>
                    </li>
                  );
                });
              }
            }

            class Content extends React.Component { //child of AppContainer
              render() {
                return(
                  <div>
                    <h1 className="page-header">{this.props.selectedContact.name}</h1>
                    <h3 className="sub-header">{this.props.selectedContact.phone}</h3>
                    <h6 className="sub-header">{this.props.selectedContact.address}</h6>
                    <h6 className="sub-header">{this.props.selectedContact.notes}</h6>
                  </div>
                );
              }
            }


            ReactDOM.render(
              <AppContainer />, document.getElementById('app')
            );
html, body, #app, .container-fluid, .row {
  height: 100%;
}
.sidebar {
    z-index: 1000;
    display: block;
    padding: 20px;
    overflow-x: hidden;
    overflow-y: auto;
    background-color: #f5f5f5;
    border-right: 1px solid #eee;
		height:100%;
}
.active {
  background-color: blue;
  color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

<div id="app">
      </div>

2
  • 1
    Add a prop to your child component that will accept a function reference and call this function with necessary value as parameter. Commented Nov 17, 2016 at 12:26
  • Have you tried onClick={this.updateContact.bind(this)} for the ContactNav click handler? Commented Nov 17, 2016 at 13:40

2 Answers 2

3

You can pass it through as props. I will take a simple example for passing objects from child to parent component

Scenario

Let's say we have multiple card item to be displayed and each of them have its ID, Name, Date etc attributes. Each of the card item has delete functionality/operation, we can take this delete operation as a component (which will be a child component of the item component) lets see how we can pass values to the parent from the child.

Lets 1st see the child component (Delete Component)

/**
 * Delete component
 */

import * as React from 'react';
import { IconButton, Button } from 'react-toolbox/lib/button';


interface IDeleteProps {
    onDeleteClick: (e:boolean) => void;
}


class Delete extends React.Component<IDeleteProps, {}> {

    constructor(props) {
        super(props);
    }
    public onClickTrigger = () => {
        this.props.onDeleteClick(true);
    }
    public render() {
        return (

            <Button icon='inbox' label='Delete' onClick={this.onClickTrigger} flat primary />

        );
    }
}

export default Delete;

Here you can see we are trying to check whether the button is clicked or not, and main intention is to notify the parent component (Item Component) to do further process, onDeleteClick method here is used as a prop to pass the boolean value to parent component, Now lets see the Parent Component (Item)

/**
 * Item component
 */

import * as React from 'react';
import './styes.scss';
import Edit from '../item/operation/Edit';
import Delete from '../item/operation/Delete';
import View from '../item/operation/View';
const ReactGauge = require('react-gauge').default;

interface IItemProps {
    item: any;
    onDeleteChangeItem: (id: number) => void;
}


class Item extends React.Component<IItemProps, {}> {

    constructor(props) {
        super(props);
    }
    public deleteClickedEvent = (e: boolean) => {
        if (e === true) {
            this.props.onDeleteChangeItem(this.props.item.id);
        }
    }

    public render() {
        const dummyText = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.';
        const itemStyle = {
            backgroundImage: `url('${this.props.item.url}')`
        };

        return (
            <div style={itemStyle} className='AudienceGridItem'>

                <span className='name'>{this.props.item.id}</span>
                <span className='name'>{this.props.item.name}</span>
                <span className='name'>{this.props.item.customerCount}</span>
                <span className='name'>{this.props.item.lastEdited}</span>
                <span className='name'>{this.props.item.lastRerun}</span>
                <ReactGauge
                    value={this.props.item.percentage}
                    width={140} height={70}
                    />
                <Edit />
                <Delete onDeleteClick={this.deleteClickedEvent} />
                <View />
            </div>

        );
    }
}

export default Item;

You could see in the Item component, Delete component is called in the render method and onDeleteClick is called and assigned to a method deleteClickedEvent where within that method it checks the boolean value passed and progress accordingly. This was my example which i tried when i was learning parent children component interactions in react, Hope this helped you to understand to some-level, if i am not making any sense please point me out

Sign up to request clarification or add additional context in comments.

Comments

2

Don't use refs in this case. You ref (this._obj) is getting continually overwritten during your loop. Pass a reference to your item to the click handler itself. So, change these:

<a href="#" key={i.id} onClick={this._handleClick.bind(this) } ref={(input) => this._obj = i}>
  {i.name}
</a>

_handleClick(){
  event.preventDefault();
  console.log(this._obj);
  let obj = this._obj
  this.props.updateContact(obj);
}

to these:

<a href="#" key={i.id} onClick={() => this._handleClick(i) }>
  {i.name}
</a>

_handleClick(obj){
  event.preventDefault();
  this.props.updateContact(obj);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.