passing data from child to grandparent - reactjs

I'm new to React and still learning.
I'm trying to pass data from child to grandparent. So far I reach to parent and I`m stuck.
Child component:
export class Child extends React.Component{
constructor(props) {
super(props);
this.state= {
counterChild: 5
}
}
render() {
return(
<div>
<span>Child: {this.state.counterChild}</span><br />
<button onClick={this.props.data(this.state.counterChild)}>Click me</button>
</div>
);
}
}
Parent component:
export default class Parent extends React.Component{
constructor(props){
super(props);
this.state= {
counterParent: 0
}
}
updateParent(value) {
return() => {
this.setState({
counterParent: value
});
}
}
componentWillMount(){
this.props.data(this.state.counterParent)
}
render(){
return(
<div>
<span>Parent: {this.state.counterParent}</span>
<Child data={this.updateParent.bind(this)}/>
</div>
);
}
}
in child component i use a button
and here i guess i have to use componentWillMount in order to send to grandparent..but it does not reach
Grandparent component:
export default class Grandparent extends React.Component{
constructor(props){
super(props);
this.state = {
counterGrandparent: 0
}
}
updateGrandparent(value){
return() => {
this.setState({
counterGrandparent: value
});
}
}
render(){
return(
<div>
<span>Grandparent: {this.state.counterGrandparent}</span>
<Parent data={this.updateGrandparent.bind(this)}/>
</div>
);
}
}
What did I do wrong here?

As you may have figured out, data is passed down the component tree in the form of props, and up in the form of prop callback functions. When something happens in a child, you call the callback to inform the parent. The parent then updates its state and passes the new state to the child as a prop.
In your case, you have three nested components, each with their own state. Typically, only a parent "container" component will have state, and child components will be stateless. So let's remove the state from the Child and Parent components. The Child component interacts with the user with a button, so whenever the button is pushed, the event handler is called and the data flows up the tree using callbacks. I added some borders and padding to make the nesting clear:
Part of the problem lies in the onClick handler on your button. Event handlers should be function references, but you have used a function call. So your child might be like below. Note the counter prop that receives the current state, and the updateParent prop that allows the Child to update the Parent.
import React from 'react';
const boxStyle = {
border: '1px solid red',
padding: '5px'
};
export class ChildWithButton extends React.Component {
handleClick(event) {
this.props.updateParent(this.props.counter + 1);
}
render() {
return(
<div style={boxStyle}>
<div>Child: {this.props.counter}</div>
<button onClick={this.handleClick.bind(this)}>
Add 1
</button>
</div>
);
}
}
The Parent component passes the current state down in the counter prop, and lets the Child component change the state by calling the updateParent callback that it received as a prop:
export class Parent extends React.Component{
updateParent(value) {
this.props.updateGrandparent(value);
}
render() {
return(
<div style={boxStyle}>
<div>Parent: {this.props.counter}</div>
<ChildWithButton
counter={this.props.counter}
updateParent={this.updateParent.bind(this)} />
</div>
);
}
}
The Grandparent component holds the state, passing it down to the Parent in counter and allowing it to update it with updateGrandparent. It should be noted that Grandparent has no knowledge of Child, only of Parent.
export default class Grandparent extends React.Component {
constructor(props) {
super(props);
this.state = {counter: 5};
}
updateGrandparent(value){
this.setState({counter: value});
}
render() {
return (
<div style={boxStyle}>
<div>Grandparent: {this.state.counter}</div>
<Parent
counter={this.state.counter}
updateGrandparent={this.updateGrandparent.bind(this)} />
</div>
);
}
}
You should avoid using componentWillMount as it will be removed in a future version of React.
You should also name the function you pass down in props something other than data. Function names are typically verbs.
There was more than one thing wrong with your code, so I hope this answers your question.

Related

React Passing Data Between Components that are Nested in Same Component?

In my situation I have a root component called App.
Inside my App component render function I have two other react components. ModalWrapper is the first component and it has a method called closeModal() which I would like to be able to call from within its child component AddUser. Is there anyway to pass this method down to addUser without moving the AddUser call to the ModalWrapper render function?
render() {
return (
<div>
<ModalWrapper title="Add Member" buttonText="Add Member">
<AddUser />
</ModalWrapper>
<div>
)
}
class Parent extends Component {
constructor(props){
super(props);
this.closeModal = this.closeModal.bind(this);
}
closeModal(){
alert('close Modal');
}
render(){
return(
<div>
<ChildComponent closeModal = {this.closeModal} />
</div>
);
}
}
class ChildComponent extends Component {
constructor(props){
super(props);
}
componentDidMount(){
this.props.closeModal();
}
render(){
return(<div> </div>);
}
}
Let's say you have parent component and you define a function in parent component and want to use that function in to the child component. You can use parent component function in to child component by passing it via props. and call parent function in child component via props.

React route rendered component not triggering setState on parent

I have an issue with React Router v.4. When a route is matched in the parent component and the child component is rendered, the componentDidMount method of the child triggers the showAlbum method passed to it by the parent.
However, though the showAlbum method is triggered, the setState method inside it does not update the state of the parent. When the child component is unmounted, the showAlbum method works correctly, just as it does on the subsequent calls.
Any idea where do I go wrong?
Thank you!
Parent component:
export default class AlbumContainer extends Component {
constructor(props) {
super(props)
this.state = {
showAlbum: false
}
}
showAlbum() {
this.setState({
showAlbum: !this.state.showAlbum
})
}
render() {
return (
<section className="border">
<div className="u-innerContainer">
<Route path='/:linkName' render={ (props)=><Album showalbum={ this.showAlbum.bind(this) }/> } />
</div>
</section>
)
Child component:
export default class Album extends Component {
render() {
return (
<section>
<div className="u-innerContainer">
<Link to="/">Back</Link>
<h3>{ 'title' }</h3>
<section>{ 'content' }</section>
</div>
</section>
)
}
componentDidMount() {
this.props.showalbum()
}
componentWillUnmount() {
this.props.showalbum()
}
}
I am sorry, I haven't got time to verify the solution, but your problem can be caused by setting of state based on previous state value.
https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.
Try to set new state by this way:
showAlbum() {
this.setState(prevState => ({
showAlbum: !prevState.showAlbum
}));
}
Please add constructor in Child component :
constructor(props) {
super(props)
}

Render a component when another component is clicked

I want to render BlackSpark when RedSpark is clicked, but I'm not sure how to change the state of a component in another component. I know how to set state in the component itself, but how do I affect another component when I click a different component?
class BlackSpark extends React.Component {
render() {
return (
<div className="black"></div>
);
}
}
class RedSpark extends React.Component {
render() {
return (
<div className="red"></div>
);
}
}
class App extends React.Component {
render() {
return (
<div>
<BlackSpark />
<RedSpark />
</div>
);
}
}
In React, there's a concept of component composition as you've already embraced -- it allows you to accomplish what you want by rendering children based on the parent's state, another key concept known as lifting state up. What this means, is if you have mutually dependent components, create a single parent which composes them, and have state in the parent control the presentation and logic of the children. With the parent App, you can keep your state inside App, and based on App's state, conditionally render whatever you want -- either BlackSpark or both. For example, using the logical && operator:
{condition && <Component />}
This will only render <Component> when condition is truthy, or else it will not render anything at all (except for when condition is 0). Applying it to this situation, try adding state to your App component to utilize conditional rendering.
There's another key concept you need to understand: component props. They are essentially inputs to a component, certain properties passed to the component to tell how it should behave -- like attributes on regular HTML elements such as input placeholders, URLs, and event handlers. For example:
<Component foo="bar" bar={3} />
This will pass the props foo and bar down to Component with the values "bar" and 3 respectively and are accessible through this.props. If you were to access this.props.foo inside the Component component it would give you "bar". If you pair this up with composition, you can accomplish what you want:
class Example extends React.Component {
constructor() {
super();
this.state = {
showHello: true
}
this.handleChange = this.handleChange.bind(this);
}
handleChange() {
this.setState(prevState => ({
showHello: !prevState.showHello
}));
}
render() {
return (
<div>
{this.state.showHello && <Child2 />}
This is a test.
<Child1 onClick={this.handleChange} />
</div>
);
}
}
class Child1 extends React.Component {
render() {
return <div onClick={this.props.onClick}>Click me!</div>
}
}
class Child2 extends React.Component {
render() {
return <div>Hello!</div>
}
}
ReactDOM.render(<Example />, document.getElementById('root'));
<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>
<div id="root"></div>
The above example lifts state up by having a parent compose the children and maintain the state. It then uses props to pass down an onClick handler to Child1, so that whenever Child1 is clicked, the state of the parent changes. Once the state of the parent changes, it will use conditional rendering to render <Child2> if the condition is truthy. Further reading at the React documentation and on the logical && operator.
I know how to set state in the component itself, but how do I affect another component when I click a different component?
The recommended way to do it would be to create a parent component that has the state. You'd then use that state to determine when to render the other child component.
I want to render BlackSpark when RedSpark is clicked, but I'm not sure how to change the state of a component in another component. Also, what if I want to hide BlackSpark when GreenSpark is clicked and GreenSpark is inside BlackSpark?
In this case, here's how you'd do it.
const GreenSpark = ({ onClick }) => (
<button className="green" onClick={onClick}>X</button>
)
const BlackSpark = ({ onClick }) => (
<div className="black">
<GreenSpark onClick={onClick} />
</div>
)
const RedSpark = ({ onClick }) => (
<div className="red" onClick={onClick}></div>
)
class Spark extends React.Component {
constructor(props) {
super(props)
this.state = {
showBlack: false
}
this.boundShowBlack = this.showBlack.bind(this)
this.boundHideBlack = this.hideBlack.bind(this)
}
showBlack() {
this.setState({ showBlack: true })
}
hideBlack() {
this.setState({ showBlack: false })
}
render() {
return (
<div>
<RedSpark onClick={this.boundShowBlack} />
{this.state.showBlack && <BlackSpark onClick={this.boundHideBlack} />}
</div>
)
}
}

How can I change value of prop in react?

How to change the value of props, how to setProps, suppose the value of this.props.contact.name is John, I want to change it to Johnny.
How can I do this?
For example:
changeValue(){
this.props.contact.name='Johnny'
}
You would change the prop in the parent component, as that is what holds the value of the prop itself. This would force a re-render of any child components that use the specific prop being changed. If you want to intercept the props as they're sent, you can use the lifecycle method componentWillReceiveProps.
I would suggest rather then change the props value you can pass the function into props and then change the parent component state so it will change the child component props like
your Parent Component should be
class SendData extends React.Component{
constructor(props) {
super(props);
this.state = {
images: [
'http://via.placeholder.com/350x150',
'http://via.placeholder.com/350x151'
],
currentImage: 0
};
this.fadeImage=this.fadeImage.bind(this);
}
fadeImage(e) {
e.preventDefault();
this.setState({currentImage: (this.state.currentImage + 1) % this.state.images.length})
}
render()
{
return(
<FadeImage images={this.state.images} currentImage={this.state.currentImage} fadeImage={this.fadeImage}/>
)
}
}
your Child Component should be like
class FadeImage extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="image">
<CSSTransitionGroup
transitionName="example"
transitionEnterTimeout={300}
transitionLeaveTimeout={300}
>
<section>
<button className="button" onClick={this.props.fadeImage.bind(this)}>Click!</button>
<img src={this.props.images[this.props.currentImage]}/></section>
</CSSTransitionGroup>
</div>
);
}
}
Please check working example here Demo
Props are immutable, that means you can not change them!
https://facebook.github.io/react/docs/components-and-props.html
If you want to save a new value build it as a state and use this.setState(...)
https://facebook.github.io/react/docs/state-and-lifecycle.html

React - How do I access a function in another component?

My structure is as such:
<ParentComponent />
<Child 1 /> <Child 2 />
I have a function in <Child 1 />. Since <Child 1 /> controls the grid-layout, and <Child 2 /> is a Navbar with buttons, I want to have a button in <Child 2 /> which will reset some parameters in <Child 1 />.
How do I achieve this? As far as I can see, refs will only be able to go one "step" up the tree, not down.
There isn't any obvious way this function can be invoked from the parent component. Is there any way here? All the solutions I can think of aren't really following the React-mindset, namely the unidirectional data-flow.
You can make the parent component as a container for both components. So all the states and functions are handled in the parent components and pass them to the other components as props.
e.g.
class Parent extends React.Component {
constructor() {
super();
this.state = {
controls: controls
}
}
onClick = (dataFromChild2) => {
//Resetting
this.setState({controls: dataFromChild2})
}
render() {
return (
<div>
<Child1 gridControl={this.state.controls}/>
<Child2 onClick={this.onClick}/>
</div>
)
}
}
You can access the gridControl and onClick from this.props in the children components
UPDATE
Think of it this way, you have the Parent component with the states and function needed to handle the data. The children components take those data and update their states accordingly.
Let's Say the Parent Component is something like this:
class Parent extends React.Component {
constructor() {
super();
this.state = {
gridControl: {}
}
}
onChild2ButtonClick = (dataFromChild2) => {
this.setState({
gridControl: dataFromChild2
});
};
render() {
return (
<div>
<Child1 controls={this.state.gridControl}/>
<Child2 onClick={this.onChild2ButtonClick}/>
</div>
);
}
}
Child2 Component is something like this:
class Child2 extends React.Component {
constructor() {
super();
}
onClick = () => {
var data = {};
this.props.onClick(data);
};
render() {
return (
<div>
<button onClick={this.onClick}/>
</div>
);
}
If you're using states for Child1, and don't want to change them to props with function in the Parent component to handle them, then you update the state in the componentWillReceivePropsmethod with the new props received from the parent component, so that the props sent will match the states used in Child1 component.
Hope this will clear things up.
If your structure looks something as the following:
<ParentComponent>
<div>
<Child1 />
<Child2 />
</div>
<ParentComponent />
Both Child1 and Child2 should "communicate" through ParentComponent.
if Child2 will notify ParentComponent about a button click event then it can re-render Child1 with appropiate props accordingly or fire a function that Child1 gets as a prop. this is a basic flow in react.js
As an example consider a House component that has a Button and a Door child components. the Button will toggle opening and closing of the Door.
class House extends Component {
constructor(props) {
super(props);
this.state = {
isOpened: props.isOpened,
};
this.toggleOpenDoor = this.toggleOpenDoor.bind(this);
}
toggleOpenDoor() {
this.setState({
isOpened: !this.state.isOpened
});
}
render() {
return (
<div>
<Button onClick={this.toggleOpenDoor} />
<Door isOpened={this.state.isOpened} />
</div >
);
}
}
House.propTypes = {
isOpened: React.PropTypes.bool
};
House.defaultProps = {
isOpened: true
};
export default House;
On each change of this.state.isOpened the Door will re-render with the new value as prop
METHOD 1:
For this you need you need to maintain a store. On clicking button in your <Child2 /> component update the variable in the store. Read the updated variable in the store and if it has change update values in your <Child1 /> component. You can user either flux, redux, mobx etc.. as the store choices, but I would say you can start with redux.
METHOD2:
If you don't want to use store, keep a state in your <Parent /> and on button click in <Child2 /> update your state in parent through a callback function. Pass this state value as props to <Child1 /> and make changes if the prop is present.

Resources