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

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.

Related

Call back not working when Link is clicked in react router

I've been trying to send a call back to parent component C from child component A to set state in parent C! This state will be sent to another child component B. I have a link component in A which calls the component in B but the child component needs the state from parent component and when I click on the link in A the call Back is not being called but I want it to be called.
Class C extends react.Component
{
constructor(props: any)
{
super(props);
this.state={
somestate: '',
}
}
CallBack(somestate:string)
{
this.Setstate({somestate, somestate},()=>{console.log(this.state.somestate);});
}
render()
{
return(
<A CallBack={this.CallBack} />
<Route path='/somestate' >
<B somestate={this.state.somestate} />
</Route>
)
}
}
Class A extends React.Component
{
constructor(props: any)
{
super(props);
}
callback()
{
this.props.CallBack();//causing errror when i click Link tag
}
render()
{
return(
<Link to='/somestate'>
<button onClick={this.callback()}>click me</button>
</Link>
)
}
}
Class B extends React.Component
{
constructor(props: any)
{
super(props);
}
render()
{
return(
<div>
this.props.somestate;
</div>
)
}
}
I'm not able to call the call back in props. I'm guessing we cant use call back to parent and link at the same time. So how to actually use it.
According to the React Router documents you should pass others props like onClick as bellow:
<Link to="/somestate" onClick={this.callback} className="some-classname">Click me</Link>
Also you can pass className so to shape the link as you want.

passing data from child to grandparent

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.

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>
)
}
}

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.

How to invoke a function in parent component from deeply nested child component using redux

class Parent extends React.Component{
constructor(props){
super(props);
this.clicked = this.clicked.bind(this);
}
getChildrenValues(){
console.log("Children values");
}
render(){
return <div>
Parent
<Component1>
<Component2>
<Child />
</Component2>
</Component1>
</div>
}
}
class Child extends React.Component{
constructor(props){
super(props);
this.clicked = this.clicked.bind(this);
}
clicked(){
this.props.dispatch({type: "InvokeParent"});
}
render(){
return <div>
<button onClick = {this.clicked}>Click Here</button>
</div>
}
}
how to invoke getChildrenValues function from "Child" component. I am trying to get all children values from parent component and submit but I do not know how to trigger that function in redux. In flux I used to do addChangeListener and trigger that function.
Just based on your example, I would say this situation won't involve redux at all. Redux is a tool for managing global state. Nothing in this example is touching state.
For this example code to work pass your method down as a prop and invoke it on click. This can be messy if depending on how nested the child component is.
class Parent extends React.Component{
constructor(props){
super(props);
this.clicked = this.clicked.bind(this);
}
getChildrenValues(){
console.log("Children values");
}
render(){
return <div>
Parent
<Component1>
<Component2>
<Child invokeParent={this.getChildrenValues} />
</Component2>
</Component1>
</div>
}
}
class Child extends React.Component{
constructor(props){
super(props);
this.clicked = this.clicked.bind(this);
}
clicked(){
this.props.dispatch({type: "InvokeParent"});
}
render(){
return <div>
<button onClick = {this.props.invokeParent}>Click Here</button>
</div>
}
}

Resources