So I am following video tutorials by Max on Udemy and in one of the lectures he is trying to explain Ref Api's in react 16.3
So here is what he did, Inside on of the container class (not App.js) he created a property known as this.lastref = React.createRef(); and then created a ref tag in return JSX code which looks like this ref={this.lastref} (This is the parent component)
Now in child component he created a method which looks like this
myFocus () {
this.lastref.current.focus()
}
and then in parent component, he again did something like this in componentDidMount lifecycle
componentDidMount() {
this.lastref.current.myFocus()
}
Now here are two questions which I have.
[Question Part]
First: How can he use this.lastref in child component? Is this because of the uni-directional (or one directional) flow from Parent to child (this.lastPersonRef is referred from ref={this.lastPersonRef} ?
Second: myFocus I believe happens to be static method so shouldn't he initiate it before using it?
[Code Example]
Here is what Parent Component should look like -> [person.js]
import React, { Component } from 'react';
import Person from './persons/person-s';
class Cpersons extends Component {
this.lastref = React.createRef()
componentDidMount() {
this.lastref.current.myFocus()
}
render (
return {
<Person
key={el.id}
click={this.props.cpdelete.bind(index)}
ref={this.lastref}
name={el.name}
age={el.age}
changed={(event) => this.props.cpchanged(event, el.id)} />
});
}
}
export default Cpersons
and this should be my child component -> [person-s.js]
import React, { Component } from 'react';
class Cppersons extends Component {
myFocus () {
this.lastref.current.focus()
}
render() {
//something
return (
<div> Something </div>
)
}
}
export default Cppersons;
ref has changed a lot in the React world and documentation regarding it is wildy different. I suggest you use the callback method.
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.otherComponentRef = null; // Will be set after the first render
}
render() {
return [
<OtherComponent ref={el => this.otherComponentRef = el} />,
<ChildComponent reference={this.otherComponentRef} />
];
}
}
First: How can he use this.lastref in child component? Is this because
of the uni-directional (or one directional) flow from Parent to child
(this.lastPersonRef is referred from ref={this.lastPersonRef} ?
when a ref is created inside a class component like this,
this.myRef = React.CreateRef();
this.myRef is assigned a null value. Later when the component is mounted, React assigns this.myRef an object with the current property making this.myRef.current an object containing either:
the dom element that the ref is attached to, or
the component that the ref is attached
In your code, lastref is attached to the Person component like so,
<Person ref={this.lastref} .../>
which at
componentDidMount() {
this.lastref.current.myFocus()
}
React assigns the Person instance (component) to this.lastref.current, like this
// ~ with a bit of React magic under the hood
this.lastref.current = new Person();
Since myFocus is a method on the instance, it can be called by this.lastref.current.myFocus()
I encourage you to read more about React Ref and its expected behavior from React docs. If you find yourself stuck, you can read about how class inheritance work in Javascript which gives more insight to what is going on behind the scenes.
Second: myFocus I believe happens to be static method so shouldn't he
initiate it before using it?
it's really just the syntax being used from a different Javascript specification
class P {
constructor(props) {
super();
this.myRef = props.myRef
}
myFocus() {
console.log(this.myRef)
}
}
is equivalent to
class P {
myFocus() {
console.log(this.props.myRef)
}
}
in the eyes of the babel-loader from Babel which transpiles the Javascript in a typical React application created with create-react-app. myFocus will be a method of the Instance when it is instantiated in both cases.
Related
So I am following some React tutorials and the lecturer is trying to explain forward API's and ref API's.
So we have a children which looks like this
import React, { Component } from 'react';
class Cppersons extends Component {
myFocus () {
this.lastref.current.focus()
}
render() {
//something
return (
<div> Something </div>
)
}
}
export default Cppersons;
Note: this in above code
myFocus () {
this.lastref.current.focus()
}
In the above code, we created this.lastref first on the parent component hence I think it is coming from there (passing a ref from parent to child)
Here is parent component
import React, { Component } from 'react';
import Person from './persons/person-s';
class Cpersons extends Component {
this.lastref = React.createRef()
componentDidMount() {
this.lastref.current.myFocus()
}
render (
return {
<Person
key={el.id}
click={this.props.cpdelete.bind(index)}
ref={this.lastref}
name={el.name}
age={el.age}
changed={(event) => this.props.cpchanged(event, el.id)} />
});
}
}
export default Cpersons
So my question is that how can we use myFocus in the parent when the method is defined in the children? plus how does myFocus work here?
As DOC says.
The value of the ref differs depending on the type of the node:
When the ref attribute is used on an HTML element, the ref created in the constructor with React.createRef() receives the underlying DOM element as its current property.
When the ref attribute is used on a custom class component, the ref object receives the mounted instance of the component as its current.
So said that and by looking at your code you are using the ref in your custom class component , that means this.lastref.current is an instance of Person.
In your case you are calling this.lastref.current.myFocus().
I expect that you have defined the myFocus method within the class Person.
Having that ref on Person means you can call any methods you have defined within the Person Component.
Here is a component:
export default class MyComponent extends React.Component {
componentWillReceiveProps(newProps) {
console.log('RECEIVED PROPS');
}
render() {
return <div>{this.props.foo}</div>
}
}
Here is a wrapper/higher-order-component:
const withSomething = (ComponentToWrap) => {
render() {
return <ComponentToWrap {...this.props} />
}
}
Here is a functional component that wraps MyComponent in withSomething:
export default function WrappedComponent(props) {
const Component = withSomething(MyComponent);
return <Component ... some props ... />
}
Result: props-related lifecycle functions (such as componentWillReceiveProps) in MyComponent never fire, even when I update the props.
What is up with this? Do props-based lifecycle methods not work on wrapped components?
The problem is that since the line that creates the wrapped component is contained in the functional component, it basically creates a new component every time the functional component renders.
This line ends up being included in WrappedComponent's render method:
const Component = withSomething(MyComponent);
...which means Component gets overwritten at every render.
Another clue is to put a componentDidMount() into MyComponent -- it'll fire every time the props update.
Solution is to create the wrapped component somewhere OUTSIDE the functional component, or outside the render method if you are using a regular class component.
I have a component like this:
import React, { Component } from 'react';
class MyComponent extends Component {
constructor(props, context) {
super(props, context);
this.state = {
isActive: false,
}
}
showMyComponent() {
this.setState({
isActive: true,
});
}
hideMyComponent() {
this.setState({
isActive: false,
});
}
render() {
return (
<div>
<h1>Compoent Here</h1>
</div>
);
}
}
export default MyComponent;
Now, on my index.js I am adding several components.
...
<Header />
<Nave />
Can I now do something like this here:
MyComponent.showMyComponent();
Like you normally call a function?
If not, how is this done?
You can use references. In your render() method you can get the ref. e.g.
<MyComponent ref={ref => {this.myComponent = ref}}/>
You need to create a field myComponent and assign it to it. With that you can call it like this.myComponent.showMyComponent()
See here Refs and the DOM
Use State
You are thinking about react wrong. You should not have to call a components function like this ever.
You can pass a prop to the component that will make the component hide or show.
or wrap the component in a if in the parent. Use the parents state to hide or show the component.
Like
if (someCondition) {
<MyComponent />
}
It's doable, even if some people hates this option, cause it's not the official React way, true.
You can define any public method on your component classes (such as a reset method on a Typeahead) and call those public methods through refs (such as this.refs.myTypeahead.reset()). In most cases, it's clearer to use the built-in React data flow instead of using refs imperatively.
But However, thinking out of the box, is not forbidden so you can use refs for this.
class Parent extends Component {
onSomeThing() {
// Call some method of myChild
this.myChild.myChildsPublicMethod()
}
render() {
return <MyChild ref={ref => { this.myChild = ref; }} />
}
}
// MyChild
// Just as demo using Pure components here.
// You could use the normal class notation..
const MyChild = () => <div>Ola</div>;
MyChild.someMethod = () => console.log('Ola');
More here https://zhenyong.github.io/react/docs/more-about-refs.html
There are two component in react project.
1, Parent
2, Child
Now, I'd like to use childMethod in Parent component.
In some pages of stackoverflow, everyone said refs is effective.
But in my project, it's not working.
class Parent extends Component {
parentMethod(){
this.refs.child.childMethod();
}
render() {
return (
<Child ref='child'/>
);
}
}
class Child extends Component {
childMethod() {
alert('You made it!');
}
render() {
return (
<h1 ref="hello">Hello</h1>
);
}
}
When I use above code, there is one error code in browser console.
_this3.refs.child.childMethod is not a function
I'd like to use child method, so I have 2 questions.
1, What's "_this3" ? How can I use refs correctly?
2, Do you have any other idea about it?
class Parent extends React.Component {
constructor(props) {
super(props);
// binding methods to the class so they don't lose 'this'
// when invoked from another environment.
this.parentMethod = this.parentMethod.bind(this);
this.setChildRef = this.setChildRef.bind(this);
}
parentMethod() {
this.childNode.childMethod();
}
// intentionally avoided using an arrow fuction inside JSX
// for we don't want a new anonymous fn created on every render.
setChildRef(node) { // receives reference to component as argument
this.childNode = node;
}
render() {
return (
<div>
<Child ref={this.setChildRef}/>
<button onClick={this.parentMethod}>Parent Button - Click me :)</button>
</div>
);
}
}
class Child extends React.Component {
childMethod() {
alert('You made it!');
}
render() {
return (
<h1>Child</h1>
);
}
}
Working fiddle: https://jsfiddle.net/free_soul/9vrLrw8h/
What's "_this3"?
Probably a variable that you may see in browser while debugging. It just represents an execution context.
How can I use refs correctly?
It is preferred to treat the ref as a callback attribute and no longer depend on the refs Object. If you do use the refs Object, avoid
accessing refs of descendant components. You should treat refs as a
private accessor and not part of a component's API. Treat only the
methods exposed on a component instance as its public API.
Can I use an instance of a reactJS component to render a component.
Eg, Let's say my reactJS component is
class myComponent extends Component{
constructor(props){
super(props)
this.state = {
next:false
}
this.alertSomething = this.alertSomething.bind(this);
this.showNext = this.showNext.bind(this);
}
showNext(){
console.log('wow');
console.log(this.state, this, this.state.next);
this.setState({next:true});
}
alertSomething(){
alert('Alert Something')
console.log(this.state, this, this.state.next);
this.setState({next:true});
}
render(){
return(
<div className='column'>
</div>
)
}
}
export default myComponent
Now, inside my another component can I do;
let x = new displayContent.renderComponent();
render(
<x />
//or
<x.render />
)
// I tried both it didn't work, I thought there mush be some other way to achieve this, after all every component is just a javascript object.
Also at the same time, can I call function to make change in its state. Like.
x.someFunction();
where someFunctino is inside that react component, doing setState.
Is it possible? OR am I missing something?
Edit: I clearly understand that when you want to render a react component, you can always do, <component />.
This question is just out of curiosity, can this be done? if not, then why?, I mean how is that different from other javascript objects.
Well, you can use the React.createElement method to render a component:
React.createElement(Component, params)
but with JSX, this is the same:
<Component />
Refer to Multiple components in the React documentation.
This is not how you're supposed to use React. You don't have to handle object instantiations ; React do this for you. Use composition instead.
render() {
return (
<myComponent />
)
}
Also, if you want to set the state of a child component from a parent component, you should probably move the logic in the parent.
Probably you are looking for something like this.
import React, { Component } from "react";
import CamCapture from './CamCapture.js';
export default class ProctorVideoFeed extends Component{
constructor(props) {
super(props);
this.Camera = React.createElement(CamCapture);
}
//this.handleVideoClick = this.handleVideoClick.bind(this);
render(){
return(
<div>
<span>{this.Camera}</span>
<button onClick = {this.Camera.StopRecording}>Stop</button>
</div>
)
}
}
Here StopRecording is a function defined inside CamCapture class.