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 ponent 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 pletely 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=".1.0/react.min.js"></script>
<script src=".1.0/react-dom.min.js"></script>
<link rel="stylesheet" href=".3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<div id="app">
</div>
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 ponent 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 pletely 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./ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.1.0/react-dom.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn./bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<div id="app">
</div>
Share
Improve this question
edited Nov 17, 2016 at 15:27
Pineda
7,5933 gold badges33 silver badges47 bronze badges
asked Nov 17, 2016 at 12:24
Thomas BraceThomas Brace
431 silver badge5 bronze badges
2
- 1 Add a prop to your child ponent that will accept a function reference and call this function with necessary value as parameter. – Rajesh Commented Nov 17, 2016 at 12:26
-
Have you tried
onClick={this.updateContact.bind(this)}
for the ContactNav click handler? – tommy Commented Nov 17, 2016 at 13:40
2 Answers
Reset to default 3You can pass it through as props
. I will take a simple example for passing objects from child to parent ponent
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 ponent (which will be a child ponent of the item ponent) lets see how we can pass values to the parent from the child.
Lets 1st see the child ponent (Delete Component)
/**
* Delete ponent
*/
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 ponent (Item Component) to do further process, onDeleteClick
method here is used as a prop
to pass the boolean value to parent ponent, Now lets see the Parent Component (Item)
/**
* Item ponent
*/
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 ponent, Delete ponent 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 ponent interactions in react, Hope this helped you to understand to some-level, if i am not making any sense please point me out
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);
}