Children to children components communication - reactjs

I have 1 parent component name [Parent-1] and 1 child component name [Child-1]. Now, I have few more other components name [Other-1] and [Other-2].
Now i am passing [Other-1] and [Other-2] component to [Child-1] component. JSX is rendering correct. How can i access [Other-1/2] component functions from [Child-1] ? or How can i pass props to [Child-1] from [Other-1/2] ?
By using refs I am able to call the [Other-1/2] functions from [Parent-1] but I want to access from [Child-1]. I tried passing refs to [Child-1] like <Child abc={() => this.refs.other1.hello()}/> or <Child abc={this.refs.other1.hello()}/> but this is not working.
By using global Event Emitter way I am able to achieve solution to my above problem. But not sure if that's the appropriate way in React.js

I think you're not using the refs properly.
When you try to give an arrow function to refs it will sometime causes error due to the ref returning null. See my question to find out why.
The example should help you understand refs
Hope this helps!
class Others1 extends React.Component {
log(){
console.log('Hello from Others1')
}
render() {
return <h1>Others1</h1>
}
}
class Others2 extends React.Component {
log(){
console.log('Hello from Others2')
}
render() {
return <h1>Others2</h1>
}
}
class Child extends React.Component{
other1Ref(el) {
el.log()
}
other2Ref(el) {
el.log()
}
render() {
const Others1 = this.props.others1
const Others2 = this.props.others2
return (
<div>
<Others1 ref={this.other1Ref}/>
<Others2 ref={this.other2Ref}/>
</div>
)
}
}
class Parent extends React.Component{
render() {
return <Child others1={Others1} others2={Others2}/>
}
}
ReactDOM.render(<Parent/>, document.getElementById('app'))
<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="app"></div>

Additionally, There can be a case where we have to pass [Others1] and [Others2] as array of object say E.g.
class Others1 extends React.Component {
log(){
console.log('Hello from Others1');
}
render() {
return <h1>Others1</h1>
}
}
class Child extends React.Component{
other1Ref(el) {
el.log();
}
render() {
// 'i' need to be counter for eg. 0, 1, 2 ...
const Others1 = this.props._array[i].type();
Other1.other1Ref();
return (
<div></div>
)
}
}
let _array = [<Others1/>, ...];
class Parent extends React.Component{
render() {
return <Child _array={_array} />
}
}
ReactDOM.render(<Parent/>, document.getElementById('app'))
By using .type() we will able to access Children function in case of array of objects/components

Related

With React, how to access the render return value of a child component

I have a React Component that replaces some content inside a string or array of strings, and I have another Component that does something similar. Both return, in their render() methods, an array of strings. Now I would like to combine them, and use the output of the second component as the input of the first one.
Here's a very simplified example of what I'm trying to achieve:
class Container extends React.Component {
render() {
return ['Hello', 'World'];
}
}
class Enhancer extends React.Component {
render() {
// Get actual content of the children,
// not the React element.
// How do I do that?
const content = this.props.children;
return content.splice(1, 0, 'Dear');
}
}
render(
<Enhancer>
<Container />
</Enhancer>
)
// Expected: HelloDearWorld
I have searched the Web and React's documentation, but I cannot find a way to do that. Is it possible to access the actual value of a child element in React?
Thanks!
Edit: Solution!
function withSpecialContent(WrappedComponent, content) {
return class extends React.Component {
render() {
return <WrappedComponent>
{ content }
</WrappedComponent>;
}
}
}
class Enhancer extends React.Component {
render() {
return content.splice(1, 0, 'Dear');
}
}
render(
withSpecialContent(Enhancer, ['Hello', 'World']);
)
// Result: HelloDearWorld
I believe what you need is HOC:
https://reactjs.org/docs/higher-order-components.html
So, I think you jsut need Container to be "in the middle" between the input and Enhancer Component. Something like the following:
class Enhancer extends React.Component {
render() {
return (
this.props.arrStr.map((str, index) => {
/* Here you have the computation made from `Enhancer`. */
return <p key={index}>Dear {str}</p>;
})
);
}
}
class Container extends React.Component {
render() {
/* Perform operations on the strings. */
const processedStrings = this.props.arrStr.map(str => str + ", how are you?");
/* You pass the processed strings to the enhancer. */
return <Enhancer arrStr={processedStrings} />;
}
}
ReactDOM.render(<Container arrStr={["Foo", "Bar", "Miz"]} />, document.getElementById('root'));
#import url(https://fonts.googleapis.com/css?family=Montserrat);
body {
font-family: 'Montserrat', sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'></div>

Pass event through nested components bottom to top

While this question has been asked before I did not find an answer. I have components nested to the level of great grandchild and I don't know how to get the data from the bottom to the top.
<Parent/>
<Child/>
<GrandChild/>
<GreatGrandChild/>
See an example: fiddle
The great grandchild is a form and I want the input data to get to the parent at the top. I had it working when it was just nested one level deep, but now that it is deeply nested it does not work. I'm not sure how to even pass the event up two levels.
I've heard using redux is possible but I wonder if there is a way to avoid it. Or, how do I avoid the nesting? Even through they are all actually separate components should I just move them into one big component? This might work but seems like bad practice?
Very simplified, you could just pass the function through all the components:
class GreatGrandChild extends React.Component {
render() {
return (
<div>
<input onChange={this.props.onChange}/>
<h2>I'm the GreatGrandChild</h2>
</div>
)
}
}
class GrandChild extends React.Component {
render() {
return (
<div>
<h2>I'm the GrandChild</h2>
<GreatGrandChild onChange={this.props.onChange}/>
</div>
)
}
}
class Child extends React.Component {
render() {
return (
<div>
<GrandChild onChange={this.props.onChange}/>
<h2>I'm the child</h2>
</div>
)
}
}
class Top extends React.Component {
constructor(props) {
super(props)
this.state = {
}
}
handleChildchange = (e) => {
console.log('child event on parent')
console.log(e.target.value);
}
render() {
return (
<div>
<Child onChange={this.handleChildchange}/>
<h2>I'm the parent</h2>
</div>
)
}
}
ReactDOM.render(<Top />, document.querySelector("#app"))
Redux is overkill for simple passing of props. You can pass props down through each child but it's easier to use the Context API like so:
Parent Component:
const MyContext = React.createContext('default');
export MyContext;
class Parent extends React.Component {
myFunction() {
//Do something here
}
render() {
return (
<MyContext.Provider value={this.myFunction}>
<ChildComponent />
</MyContext.Provider>
);
}
}
export default Parent;
Child Component:
import { MyContext } from './Parent';
class ChildComponent extends React.Component {
render() {
const { myFunction } = this.context;
return (
<div onClick={myFunction}>Click Me!</div>
);
}
}
ChildComponent.contextType = MyContext;
You can use the context as deep as you'd like, as long as you import it.
Simply pass a callback down from the parent via the props and make Sure it's passed all the way down to where you need it.
You also can pass props to your each child component in nesting and whenever values changed, you can call a parent function (nested) to get latest values in parent.

ReactJS - Call parent method from child component and await response from parent

I just started working with ReactJS so I am still getting the hang of it. I need some help with one aspect to which I found no answer. I am trying to call a function in a parent component from a child component, but I also want to receive an answer from the parent, containing some data. How can I achieve that?
Currently what I am doing is:
import Parent from './parent.js';
class Child extends React.Component {
constructor(props) {
super(props);
};
click = () => {
this.props.parentMethod();
}
render() {
<div onClick={this.click}>Hello Child</div>
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
};
someMethod() {
console.log('bar');
}
render() {
<Child parentMethod={this.someMethod}>Hello Parent, {this.props.children}</Child>
}
}
You wouldn't normally do this. Data flows from parent ยป child in React. Thus, if executing a function on Parent changes data passed to Child, your Child component would re-render.
Using your example:
class Child extends React.Component {
render() {
<div onClick={this.props.changeName}>
Hello, {this.props.displayName}
</div>
}
}
class Parent extends React.Component {
constructor(){
this.state = {
name: "Bob",
}
}
changeName = () => {
this.setState({ name: "Sally" })
}
render() {
return(
<Child
changeName={this.changeName}
displayName={this.state.name}
/>
)
}
}
In this, clicking on the div inside Child would change the name property of Parent's state, which would then be passed to Child and get re-rendered.
You can keep the data on your parent component's state and pass it to children. After calling your function this data changes in the parent, then goes back to child again. By the way, you are missing returns in your render methods. Look for it.
const Child = ( props ) => {
const click = () => {
props.parentMethod();
}
return (
<div onClick={click}>
Hello, this is Child.
Data is now: {!props.data ? "No data yet!" : props.data }
</div>
);
}
class Parent extends React.Component {
state = {
data: "",
}
someMethod = () =>
this.setState({ data: "bar"});
render() {
return (
<Child data={this.state.data} parentMethod={this.someMethod} />
);
}
}
ReactDOM.render(<Parent />, 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>

React: how can I access the methods of the class that generates JSX?

Let's say I have the following classes:
class App {
constructor() {
super();
this.pawns[3][2] = this.getRegPawn(PAWN.BLUE);
debugger; /// HERE !!!
}
getRegPawn(pawnType) {
return <RegularPawn pawnType={pawnType}/>;
}
}
class RegularPawn extends AbstractPawn {
constructor(props) {
super(props);
}
isBasicMove() {
...
}
isStrikeMove() {
....
}
return false;
}
render() {
const _this = this;
switch (this.props.pawnType) {
case PAWN.BLUE:
pawn = <div className="bluePawn" ref = {() => {return _this}}></div>;
break;
case PAWN.RED:
pawn = <div className="redPawn" ref = {() => {return _this}}></div>;
break;
}
return pawn;
}
}
My intention is to access the methods in class RegularPawn by accessing this.pawns[3][2].
The object stored in this.pawns[3][2] is:
I tried:
this.pawns[3][2].isBasicMove()
this.pawns[3][2].props.isBasicMove()
this.pawns[3][2].ref.isBasicMove()
this.pawns[3][2].props.ref.isBasicMove()
and none of them succeeded. Do you know what can help me?
In order to use functions from the child components you will need to use references instead of the return value of the createElement call from react (which is the return value of a JSX tag).
You can pass the ref callback to child components and use the returned value to assign the pawn matrix.
Here is a simple example how to use it versus what you are trying to do:
The Alert1 Button behaves as you use it, it won't work, on the other hand Alert2 button is using ref which is the way to go.
class Hello extends React.Component {
constructor() {
super();
this.child = <Child ref={(ref) => {this.child2 = ref;}} />
console.log(this.child);
}
childAllert1() {
this.child.allert();
}
childAllert2() {
this.child2.allert();
}
render() {
return (
<div>
Hello {this.props.name}
<button onClick={this.childAllert1.bind(this)} >Alert1</button>
<button onClick={this.childAllert2.bind(this)} >Alert2</button>
{this.child}
</div>);
}
}
class Child extends React.Component {
allert() {
alert("called");
}
render() {
return <div>Hello
</div>;
}
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
<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="container">
<!-- This element's contents will be replaced with your component. -->
</div>

Higher order component always rerenders ignoring shouldComponentUpdate

I have a higher order component like this
// higherOrderComponent.js
const HigherOrderComponent = Component => class extends React.Component {
shouldComponentUpdate (nextProps, nextState) {
return false
}
render () {
return <Component {...this.props} />
}
}
export default HigherOrderComponent
// myComponent.js
import HigherOrderComponent from './higherOrderComponent'
class MyComponent extends React.Component {
render () {
return <div>my component</div>
}
}
export default HigherOrderComponent(MyComponent)
// parentComponent.js
import MyComponent from './myComponent'
class ParentComponent extends React.Component {
render () {
return <MyComponent />
}
}
I explicitly return false but the component always get re-rendered. Any idea why? I ultimately want to share the "shouldComponentUpdate" across components. How can I achieve that if higher order component does not work?
since you have not specified how you are invoking your Higher Order component, based on the issue I have made a guess how you might be using it.
My Answer is based on the assumption that you are invoking your higher order function like
var MyHigherOrderFn = (HigherOrderComponent(Baar));
If Some you how you can invoke your higher order function like below into return in render, you can avoid the issue.
<HigherOrderComponent prop1="Hello" child="Child" />
Since I don;t know how invoke your function in above way(I am not sure its even possible), I have created HigherOrderComponent2 with different syntax style which can be invoked like, which in turn comply with shouldComponentUpdate
<Parent prop1="val1">
<Child>
</Parent>
import React, {PropTypes} from 'react';
/*This is simeple child component*/
class Baar extends React.Component {
render() {
return (<div>{this.props.name}</div>);
}
}
/*This is your higher order component*/
const HigherOrderComponent = Component => class extends React.Component {
shouldComponentUpdate (nextProps, nextState) {
return false;
}
render () {
return <Component {...this.props} />
}
}
/*This is another way to write higher order component*/
class HigherOrderComponent2 extends React.Component {
constructor(props) {
super(props);
}
shouldComponentUpdate (nextProps, nextState) {
return false;
}
render(){
let child = this.props.children && React.cloneElement(this.props.children,
{...this.props}
);
return <div>{child}</div>
}
}
/*Problem that you are facing how you invoke your Higher Order Compoent*/
export default class Foo extends React.Component {
constructor(props) {
super(props);
this.onHandleClick = this.onHandleClick.bind(this);
this.state={
name: 'Praveen Prasad'
}
}
onHandleClick(){
this.setState({
name:Math.random()
});
}
render() {
{'This is how you might be invoking you higher order component, at this time react render doesnt know it already exists in DOM or not'}
{'this component will always re-render, irrespective of values in shouldComponentUpdate'}
var Baaz = (HigherOrderComponent(Baar));
return (<div>
<button onClick={this.onHandleClick}>Update Name</button>
<Baaz name={this.state.name} />
{'This is another way to invoke higher order Component , and this will respect shouldComponentUpdate'}
<HigherOrderComponent2 name={this.state.name}>
<Baar />
</HigherOrderComponent2>
</div>);
}
}
I have modified your code to create a snippet and it works as intended, MyComponent.render is called only once when shouldComponentUpdate returns false.
My guess is that somehow you are using the unwrapped version of MyComponent instead of the wrapped one. Maybe a problem with your build environment?
// higherOrderComponent.js
const HigherOrderComponent = Component => class extends React.Component {
shouldComponentUpdate (nextProps, nextState) {
return false;
}
render () {
return <Component {...this.props} />
}
}
class MyComponent extends React.Component {
render () {
console.log('render');
return <div>my component</div>
}
}
const MyComponentHOC = HigherOrderComponent(MyComponent);
class ParentComponent extends React.Component {
render () {
return <MyComponentHOC />
}
}
ReactDOM.render(<ParentComponent/>, document.getElementById('container'));
ReactDOM.render(<ParentComponent/>, document.getElementById('container'));
<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="container"></div>
It is about the life cycle for a react component. When a component get initialized, it will not check shouldComponentUpdate. ShouldComponentUpdate will only be called when state/props CHANGED.
FYI the lifecycle methods call in order:
When a component is initialized:
getDefaultProps
getInitialStage
componentWillMount
render
componentDidMount
When a component has state changed:
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
When a component has props changed:
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
When a component is unmounting:
componentWillUnmount
You would need to use a different type of HOC pattern called inheritance inversion to access the lifecycle methods. Since you are overriding shouldComponentUpdate you don't call super however it is required to call super.render() inside the subclassed components render method.
Try this...
const HigherOrderComponent = () => WrappedComponent =>
class ShouldNotUpdate extends WrappedComponent {
shouldComponentUpdate(nextProps) {
return false
}
render() {
return super.render()
}
}
it's good practice to use currying so as you could annotate your classes in the future like...
#HigherOrderComponent
class MyClass extends React.Component {
render() {
return <div>something</div>
}
}
// or without annotations..
const MyNewClass = HigherOrderComponent()(MyClass)

Resources