Can't get Child Component ref object from their parent React JS - javascript

I want to reference a <div> and a <span> component from the child to the parent.
So i code something like:
class Parent extends Component {
childRef = React.createRef()
componentDidMount(){
const childRef1 = this.childRef.current.innerRef1
const childRef2 = this.childRef.current.innerRef2
//... compute with the references childRef1 and childRef2
}
render(){
return(
<ChildComponent ref={this.childRef} />
)
}
}
Inside the child i got something like:
class ChildComponent extends Component {
innerRef1 = React.createRef()
innerRef2 = React.createRef()
render(){
return(
<div ref={this.innerRef1}>
<span ref={this.innerRef2}></span>
</div>
)
}
}
I want to get the properties of those tags. Things like getBoundingClientRect(), scrollTop,etc; but from the Parent component because i can't compute it from the ChildComponent componentDidMount because those component aren't rendered yet.
That's is my current result from browser console:
As you can see, the current object shows me a null value, but inside you can see all the properties that i want to get.

As you want to get the properties of those tags like getBoundingClientRect(). I have provided the example where I called getBoundingClientRect() using ref and also I set a string into innerText of span. Please check it.
Parent Component Example
import React from "react";
import ChildComponentExample from "./ChildComponentExample";
export default class ParentComponentExample extends React.Component {
childRef = React.createRef();
componentDidMount() {
const childRef1 = this.childRef.current.innerRef1;
const childRef2 = this.childRef.current.innerRef2;
console.log(childRef2, 'childRef2');
childRef2.current.innerText = 'This is SPAN';
const rect = childRef1.current.getBoundingClientRect();
console.log(rect, 'rect');
}
render() {
return (
<ChildComponentExample ref={this.childRef}/>
)
}
}
Child Component Example
import React from "react";
export default class ChildComponentExample extends React.Component {
innerRef1 = React.createRef();
innerRef2 = React.createRef();
render() {
return (
<div ref={this.innerRef1}>
<span ref={this.innerRef2}/>
</div>
)
}
}

Related

ReactJS - How to implement a callback function from JSX

I am having a question about how to implement a callback function. In my case, I have a React app with this structure: App > Child > Button components
The problem is I do not know how to write a callback function from Button to Child
I would like to update a value in Child (e.g: inputFromButton) after clicking the button in Button Component. The handleClick() is triggered and a value will be sent to the Child component.
Could someone help me to do this?
Here is my code:https://codesandbox.io/s/nifty-stonebraker-0950w8
The App component
import React from 'react';
import Child from './Child';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 'Data from App'
}
}
handleCallback = (childData) => {
this.setState({ data: childData })
}
render() {
const { data } = this.state;
return (
<div>
<Child dataFromApp={data} />
</div>
)
}
}
export default App
The Child component
import React from 'react';
import { renderButton } from './Button';
class Child extends React.Component {
state = {
inputFromApp: "",
inputFromButton: ""
}
componentDidMount() {
this.setState({
inputFromApp: this.props.dataFromApp
})
}
render() {
const renderButtonItem = renderButton(this.props);
const inputFromApp = this.state.inputFromApp
const inputFromButton= this.state.inputFromButton
return (
<div>
<input value={inputFromApp}></input>
<br></br>
<input value={inputFromButton}></input>
<div>{renderButtonItem}</div>
</div>
)
}
}
export default Child
The Button component
import React from 'react';
export const renderButton = (props) => {
const handleClick = () => {
console.log('handleClick() props data from App: ' + props.dataFromApp)
}
return (
<button onClick={handleClick}>Click</button>
)
}
renderButton is a function component and, therefore, needs to be in PascalCase: RenderButton (although it would be better off as Button).
Move handleClick to the Child component.
Then in Button the call to handleClick should be props.handleClick since handleClick will now be a property of the props object passed into the component. We don't need to pass down the data as a prop to the button but can, instead just log the data prop passed into Child.
handleClick = () => {
console.log(`handleClick(): ${props.dataFromApp}`);
}
In Child, instead of calling renderButton, import Button, and then use that in the render passing down the handler in the props. By doing this you're making the component as "dumb" as possible so it can be reused elsewhere in the application.
<Button handleClick={this.handleClick} />

How to pass child properties/values to parent component when screen is loaded

How do I send property values from child component to parent component when the react app is loaded? I have a parent component called app.js, which renders a home component which contains a JSON component.
When the react app is loaded, my property JSONValue (defined in app.js) holds an empty string. When the react app is loaded, JSONValue in the parent component should contain the value already defined in the child JSON component. How do I manage to send these values from JSON component to APP component on initial render?
The only way I can do this as it is right now, is by changing the value in the react app --> json component. Then it sends the value from child to parent.
So:
The value of JSONValue is defined in JSON component, and is only applied to the JSONValue in app.js when a change happens in JSON component. This should be applied as soon as the react app loads.
APP.JS:
import React, { Component } from 'react';
import Home from './Components/Home';
import './App.css';
class App extends Component
{
constructor(props) {
super(props);
this.state = {
JSONValues: {
JSONValue: ""
}
}
this.changeJSON = this.changeJSON.bind(this);
changeJSON(e, JSONId)
{
const elem = e.target;
const JSONValue = elem.value;
let tmpJSONValues = this.state.JSONValues;
tmpJSONValues[JSONId] = JSONValue;
this.setState(prevState => ({
JSONValues: tmpJSONValues
}));
}
render() {
return (
<div>
<Home
JSONValues={this.state.JSONValues}
changeJSON={this.changeJSON}
/>
</div>
)
}
}
export default App;
HOME.JS:
returns:
<div>
<JSON
JSONValues={props.JSONValues}
changeJSON={props.changeJSON}
/>
</div>
JSON.JS:
import React, { Component } from 'react';
export default class JSON extends Component {
render() {
let JSONValue = "";
if(this.props.JSONValues){
JSONValue = this.props.JSONValues.JSONValue;
}
JSONValue = 'value';
return (
<div>
<textarea className="json" spellCheck={false} value={JSONValue} onChange={(e) =>this.props.changeJSON(e, 'JSONValue')}>
</textarea>
</div>
)
}
}
Normally, you create state in the parent component and then pass the data to the child through props.
In the parent, you also create a changeStateHandler that you also pass to the child component through props.
When the child needs to update its state, it uses the passed in changeStateHandler. The parent then updates its state and passes the new state back to the child through props. The child rerenders when it gets the new props.
This is a simple contrived example:
Demo.js
import React, {useState} from 'react';
export const Parent = () => {
const [counter, setCounter] = useState(0);
return (
<div>
<div>Parent says the count is now: {counter}</div>
<Child counter={counter} handleCounter={setCounter} />
</div>
);
};
const Child = ({counter, handleCounter}) => {
const incrementCounter = () => handleCounter(counter++);
const decrementCounter = () => handleCounter(counter--);
return (
<div>
<button onClick={incrementCounter}>+</button>
<button onClick={decrementCounter}>-</button>
</div>
);
};
Pass a function through child props to set the parent state on mount as below:
class Child extends React.Component {
componentDidMount(){
const jsonString = '{"foo":"bar"}';
this.props.onMount(jsonString)
}
render() {
return null;
}
}
class App extends React.Component {
state = {
jsonData: null
}
setJson = jsonData => this.setState({ jsonData });
render(){
return (
<div>
<span>parent's state jsonData:</span>
<pre>{this.state.jsonData}</pre>
<Child onMount={this.setJson} />
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('root'))
<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>

ReactJS add callback function to children component

I want to attach a callback to a already created react component, is this possible?
This is my wrapper class, I want to call the callbackToCall from the existing children:
import React from 'react';
class MyComponent extends React.Component {
callbackToCall() {
console.log("callback called.");
}
render() {
const {children} = this.props;
// Here I want to attach the callback to call
// E.g. children.props.callback = callbackToCall;
return (
<div>
MyStuff
{children};
</div>
);
}
}
Child class, which does not have any callback to the container class:
import React from 'react';
class Child extends React.Component {
render() {
return <button onClick={this.props.callback}>Click me</button>
}
}
This is the call of my component, here I don't know how to reference the callback:
<MyComponent>
<Child /* Here I cannot set the callback callback={...callbackToCall}*/ />
</MyComponent>
Given that MyComponent is a wrapper that accepts the only child and supposed to provide callback prop to it, it should be:
class MyComponent extends React.Component {
...
render() {
const child = React.cloneElement(
React.Children.only(this.props.children),
{ callback: this.callbackToCall }
);
return (
<div>
MyStuff
{child};
</div>
);
}
}
Alternatively, MyComponent can be provided with a component instead of an element through a prop, like:
class MyComponent extends React.Component {
...
render() {
return (
<div>
MyStuff
<this.props.component callback={this.callbackToCall}/>
{this.props.children};
</div>
);
}
}
This way MyComponent can additionally accept children for other purposes like <MyComponent component={Child}>...</MyComponent>.

how to render jsx of function from child component in parent component

I am having a child component a parent component. I am having a function in child component which returns some jsx what i want to do is use that function to return the same jsx in parent component but iam unable to figure out a way to do that. I am giving my minimal code:
parent component:
class App extends Component {
render() {
return (
<div className="App">
<Player ref={instance=>{this.player = instance}} />
{this.player.func('aaa.com','bbb')}
</div>
);
}
}
export default App;
Child component:
import React, { Component } from "react";
class Player extends Component {
func = (url, label) => {
return (
<button onClick={() => this.func(url)}>
{label}
</button>
)
}
render() {
return <div>1</div>;
}
}
export default Player;
Error: Cannot read property 'func' of undefined
//
Note: i know i can use the jsx in parent component by copy-pasting but iam trying to figure out a way of doing like this. I am having doubt that is it even possible
You can create a Player object and access the function using that object.
new Player().func('aaa.com','bbb')
I don't quite understand what you need exactly but I think that you're looking to pass some jsx element from the Child component to the parent component. What we can do is declare a propType callback on the child component and then implement it on the parent component like so.
import React from 'react';
class Hello extends React.Component {
constructor() {
super();
this.state = {
// this state will keep the element returned by the parent
returnElements: null
}
this.onReturn = this.onReturn.bind(this);
}
// this method will be fired when the Child component returns callback for onSomethingReturned
onReturn(element) {
this.setState({
returnElements: element
})
}
render () {
return (
<div>
<h1>Hello, React!</h1>
<Child onSomethingReturned={this.onReturn} />
{/* I am going to display the state here */}
{this.state.returnElements}
</div>
)
}
}
class Child extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
const element = <h3>this is child element</h3>;
// will call the propType callback function with a element I want to return
this.props.onSomethingReturned(element);
}
render() {
return (null);
}
}
export default Hello;

losing react component ref after I Wrapped it by injectIntl

I have an issue with getting the ref to the func in React components after I am wrapping it with injectIntl.
basically what I need is to get access to a func in the component by ref
here is what I am doing
class MainContainer extends React.Component {
constructor(props) {
super(props);
}
getSamples(){
return sth
}
render() {
return (<div>this.props.sth</div>)
}
export default injectIntl(MainContainer )
it possible to get the ref to the MainContainer after wrapped it with injectIntl?
The withRef option should be passed.
export default injectIntl(MainContainer,{ withRef: true })
The MainContainer wrapper component instance can be retrieved using
<MainContainer ref={c => { this.container = c; }} />
The wrapped component instance can be retrieved using
this.container.getWrappedInstance();
injectIntl has a forwardRef property which causes it to pass down ref to the wrapped component.
// MyComponent.jsx
// ...
export default injectIntl(MyComponent, {forwardRef: true});
// MyApp.js
import MyComponent from 'MyComponent';
class MyApp {
render() {
this.myComponentRef = React.createRef();
return <MyComponent ref={ref} />;
}
}
reference

Categories