Difference between `ref` and `innerRef` in ReactJS - reactjs

I am using two class components where I have a method that I am invoking from the parent component. and for this reason, I have to create two references using React.createRef(). But the problem is one component allows me with ref attribute and another innerRef attribute. So I want to know what is the difference.
class X extends Component {
constructor(props) {
super(props);
this.xRef = React.createRef();
this.yRef = React.createRef();
}
render() {
return (
<Xcomponent
classes={classes}
user={user}
ref={this.xRef}
/>
<Ycomponent
classes={classes}
user={user}
innerRef={this.xRef}
/>
)
}
}

innerRef is a component instance property, while ref is a component instance attribute:
When the ref attribute is a callback function, the function receives the underlying DOM element or class instance.
// Access reference within the parent component: this.xRef.current
// Access property within the component: this.props.innerRef.current
<Ycomponent ref={this.xRef} innerRef={this.xRef} />
// coolRef is an ordinary component property, you can name it as you like
<Ycomponent ref={this.xRef} coolRef={this.xRef} />
// access with this.props.coolRef.current within the component.
In conclusion, the custom component Ycomponent defines the property innerRef for the developer to pass a reference with it.
For more info see related question: Why, exactly, do we need React.forwardRef?

Related

React you cannot pass props inside a regular function but you can pass a prop through a class component

I tried making a class and pass the prop named input under the Time component and the prop renders the prop name however I do the same but instead of using a class I use a function named Kite and try to do the same thing but I get an object error in the console and nothing doesn't render on the page is there a way I can pass a prop through a regular function instead of a class?
function Kite() {
return (<h1>{this.props.kiteprop}</h1>)
}
class Time extends React.Component {
render() {
return (
<div>
<Test input="dsa" />
<Kite kiteprop="showtext" />
<div>{this.props.input}</div>
<span>{new Date().toLocaleDateString()}</span>
</div>
);
}
}
ReactDOM.render(<Time input="joe" input="[1, 2]" input="false" />, document.getElementById("root"));
A better syntax would be:
const Kite = (props) => {
return(<h1>{props.kiteprop}</h1>)
}
export default Kite;
And seperating the components into 2 pages of js.
Notice that we pass props into the params of our component, and no need to use this here.

What is the difference between forwardingRef vs callback refs in React?

As per the React.js official documentation, the below code is an example of callback refs.
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
class Parent extends React.Component {
componentDidMount(props) {
//Here, this.inputElement in Parent will be set to the DOM node corresponding to the element in the CustomTextInput
console.log(this.inputElement);
}
render() {
return (
<CustomTextInput
inputRef={el => this.inputElement = el}
/>
);
}
}
Here, this.inputElement in Parent will be set to the DOM node corresponding to the element in the CustomTextInput.
In case of forwarding ref, as per the official document,
const FancyButton = React.forwardRef((props, ref) => {
return (
<button ref={ref} className="FancyButton" data-name="My button">
{props.children}
</button>
);
});
//Parent Component
class FancyButtonWrapper extends React.Component {
constructor(props) {
super(props);
this.buttonRef = React.createRef();
}
componentDidMount(props) {
//Here this.ref will point to button element. Because of this reason, ref.current will give the value of button.
console.log(this.buttonRef.current.getAttribute("data-name"));
}
render() {
return (
//Here we are passing the ref to the child component.
<FancyButton ref={this.buttonRef} data-attr="Hello">
Click me!{" "}
</FancyButton>
);
}
}
Here, in this case, this.ref will point to the button element. Because of this reason, ref.current will give the value of the button.
Is there any difference between forwardRef and callbackRefs? We can access the child node's reference from parent in both of these cases.
I am not an expert but here are something to think about:
- callback refs are used when we need to dynamically set refs.
- Forward refs are commonly used when access to child refs are needed.
Well for the difference between the use of forwardingRef vs callback ref is in the HOC.
if you pass ref prop to HOC then inside HOC you cannot further pass it down to the enclosing component(which HOC wraps) since the props attributes does not store the ref inside it. ref is not a key ,see here: https://reactjs.org/docs/forwarding-refs.html 
so apart form this use case they work in same way.
Hope that helps !!
The difference is in the case of the ref callback, you can run side-effects when the ref changes. If you use useRef, you can access ref at any time but you will not know when it is set, or run a useEffect with the ref as a dependency
Callback refs have more control - they allow you to for example set a state when the ref is set, which will rerender the component when the component mounts, and you can use the ref node to do whatever you need.
In short - generally use useRef as it is the simplest. But ref callbacks can give you more control when needed

How to use this.refs for a list of child components [duplicate]

This question already has answers here:
How to assign refs to multiple components
(4 answers)
Closed 5 years ago.
I have a list of <Child /> component, then I used an array this.state.infos to generate these child components. How can I use this.refs to get a specific child component?
NOTE: this.state.infos = ['tom', 'mike', 'julie']; for example.
export default class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
infos: {},
};
}
// ignore logic for this.state.infos
// ...
render() {
return (
<div>
{[...this.state.infos].map((info) => {
return <Child
ref={info}
/>
})}
</div>
);
}
}
For your approach, simply write
this.refs.tom
this.refs.julia
etc...
But note that this is considered legacy API, and you shouldn't use this any more.
A better way is
refsCollection = {};
render() {
return (
<div>
{[...this.state.infos].map((info) => {
return <Child
ref={(instance)=>{this.refsCollection[info] = instance;}
/>
})}
</div>
);
}
React supports a special attribute that you can attach to any
component. The ref attribute takes a callback function, and the
callback will be executed immediately after the component is mounted
or unmounted.
The callback receives the child DOM element as the parameter, which you can then assign to a property in your parent component object. In the code above, notice how we assigned "instance" to "this.refsCollection[info]"
Of course in your case, because you defined the Child component yourself, it's not really a standard html DOM element, so the callback parameter is actually a mounted instance of your Child component object.
And then you access the mounted component instances using:
this.refsArray['tom']
this.refsArray['julia']
For more information, see this link:
https://reactjs.org/docs/refs-and-the-dom.html

Lifting up state in React

say i have this React Class. This is NOT my main component that I'm rendering. how can i pass the state i set in here UPWARDS to the parent component.
class Player extends React.Component {
constructor(props) {
super(props);
this.state = {
playerOneName: ''
}
this.selectPlayerOne = this.selectPlayerOne.bind(this);
}
selectPlayerOne(e, data) {
this.setState({playerOneName: data.value})
}
render() {
let players = [];
this.props.players.map((player) => {
players.push({text: player.name, value: player.name})
})
return (
<div className="playersContainer">
<div className="players">
<Dropdown onChange={this.selectPlayerOne} placeholder='Select Player One' fluid selection options={players} />
</div>
</div>
)
}
}
when I say parent component i mean the class that is going to display player like so:
<Player />
I.e. how can I make this.state.playerOneName available to the parent?
Hey so the point here is that you are basically passing in, from your parent component into your child component, a prop which is a function.
In parent:
handler(newValue){
this.setState({key: newValue})
}
render() {
return(
<Child propName={handler.bind(this)}>
)
}
When a change takes place in your child component, you call the function and pass in the new value as an input. This way you are calling the function in your child component, and making a change to the state of the parent component.
In your case you want to, instead of setting the state of playerOneName, pass in a function from the parent of this class and do something like this.props.functionFromParent(playerOneName) in your 'selectPlayOne' function.
It is true that the flux pattern is unidirectional, however when you're dealing with smart and dumb components you will see that data is passed from a dumb component to a smart component in this way. It is perfectly acceptable React form!
"Lifting state up" for React means that you should replace data from your child component to parent component state and pass data for presentation to child component by props.
You can do something like this to achieve your goal. Create a parent component which hold playerOneName as its state. Pass it as a prop to child component and with that also a function that changes the playerOneName whenever it is changed in the child component.
class Parent extends Component {
constructor(props){
this.state = {
playerOneName: ''
}
}
render() {
return(
<Child
playerOneName={this.state.playerOneName}
onPlayerOneNameChange={(playerOneName) => this.setState({playerOneName})}
/>
);
}
}
Use this function like this in child component to change the name of playerOneName in Parent component, like this your child component is only displaying the value of the playerOneName all the changes are done in Parent component only.
class Child = props => {
const { playerOneName, onPlayerOneNameChange } = props;
return (
<TextInput
value={playerOneName}
onChangeText={(playerOneName) => onPlayerOneNameChange(playerOneName)}
/>
);
}
By this you can use updated playerOneName in your Parent component whenever you like by using this.state.playerOneName

React component interop

I'm new to react and am working through the tutorials. I think I have a grasp on the Multiple Components parent-child explanation, but am struggling to figure out how to provide interop (in state, events, etc) between independent components. So, given the following indepent, stateful components (that have child components, etc):
ReactDOM.render(
<FooBox />,
document.getElementById('foo')
);
and
ReactDOM.render(
<BarBox />,
document.getElementById('bar')
);
Is there a way to interop between FooBox and Barbox, or do I need to nest both under ReactDOM.render? And if I do, will that still "work"?
Use case: onClick of one of Foo's children, I want to display BarBox (with stateful information from FooBars children.
Yes, you should render into a single element so that you have a "single entry point" for the application and its corresponding React DOM. Some parent component can then control whether BarBox is displayed by setting a boolean on its local state.
For example, you could pass an onClick handler via props to FooBox:
class Parent extends React.Component {
displayBarBox () {
this.setState({ displayBarBox: true })
}
render () {
return (
<div>
<FooBox onClick={this.displayBarBox.bind(this)} />
{this.state.displayBarBox &&
<BarBox />}
</div>
)
}
}
And then use this click handler in FooBox:
class FooBox extends React.Component {
render () {
// Use the click handler passed via props
// (simple example)
return <div onClick={this.props.onClick} />
}
}
FooBox.propTypes = {
onClick: PropTypes.func.isRequired
}

Resources