what is class extends React.component in React - reactjs

In this link https://reactjs.org/docs/higher-order-components.html
where explanation is of higher order component.The code is below has class extends React.component. What is this class keyword here?
function logProps(WrappedComponent) {
return class extends React.Component {
componentDidUpdate(prevProps) {
console.log('Current props: ', this.props);
console.log('Previous props: ', prevProps);
}
render() {
// Wraps the input component in a container, without mutating it. Good!
return <WrappedComponent {...this.props} />;
}
}
}

It is an unnamed class expression.
return class extends React.Component {
The above code is creating an unnamed / anonymous class by extending React.Component class, hence, creating a new React Component which wraps (returns) the WrappedComponent passed to the function logProps.
The syntax of class expression is:
const MyClass = class [className] [extends otherClassName] {
// class body
};
where the name className (and also, extends otherClassName) is optional.
And, in your code in question, it is just returning the result instead of assigning it to a variable:
return class [className] [extends otherClassName] {
// class body
};
Note that, there are two ways to create a React Component, one is by writing a function and the other is by writing a class.
And, in JavaScript, classes was introduced in ECMAScript 2015 (also knows as ES6).

Related

Class Component with new kotlin-react without legacy

The kotlin-wrappers for React was split into kotlin-react and kotlin-react-legacy in version pre.282.
In kotlin-react-legacy it is possible to create a class based component by using RComponent.
This is missing in the new kotlin-react, however both kotlin-react and kotlin-react-legacy import kotlin-react-core which contains Component.
In kotlin-react-legacy the RComponent is defined by using RBuilder, but that doesn't exist in kotlin-react which instead has ChildrenBuilder. It would be possible to create something analogous to the legacy RComponent with ChildrenBuilder, however it cannot be accessed because it is internal.
Is there any way to create a class-based React Component, similar to what is possible in kotlin-react-legacy with RComponent, in the new kotlin-react?
There is a related discussion: https://github.com/JetBrains/kotlin-wrappers/issues/1266
Which mentions a working example: https://github.com/studoverse/campus-qr/blob/master/moderatorFrontend/src/main/kotlin/webcore/ReactHelper.kt
The RComponent can be defined as follows:
abstract class RComponent<P : Props, S : State> : Component<P, S> {
constructor() : super() {
state = jso { init() }
}
constructor(props: P) : super(props) {
state = jso { init(props) }
}
open fun S.init() {}
// if you use this method, don't forget to pass props to the constructor first
open fun S.init(props: P) {}
abstract fun ChildrenBuilder.render()
override fun render(): ReactNode = Fragment.create { render() }
}
fun <S : State> Component<*, S>.setState(buildState: S.() -> Unit) {
setState({ assign(it, buildState) })
}
Then a component can be created as:
class TestComponent : RComponent<Props, State>() {
override fun ChildrenBuilder.render() {
div {
+"Hello, world!"
}
}
}
And instantiated:
TestComponent::class.react {}

Passing a class into a React component so that it can create new instances of said class?

I have a component which renders a data structure. I am trying to create an editor for that structure and want to use the same renderer, but with certain sub-components overridden. The renderer has some data that I'd like to pass into the sub-component so I thought it might be best to use a passed class which the renderer would be able to call and include the data as props. Something roughly like:
class Editor extends React.Component{
render(){
return <Renderer overrideClass={OverridenComponent}/>;
}
}
class Renderer extends React.Component{
render(){
return <this.props.overrideClass importantData="TEST"/>;
}
}
class OverriddenComponent extends React.Component{
render(){
return <div>{this.props.importantData}</div>;
}
}
I would expect that creating an <Editor/> would result in <div>TEST</div> in the DOM, but instead I am getting what is equivalent to <overridencomponent></overridencomponent>, specifically non-capitalized and with no content.
Is this sort of behavior supported in some way? Is there a better way to accomplish this sort of overridable content while still allowing the Renderer class to pass data to the overridden version?
JSX only renders components which names are Capitalized. Therefore you should save the override class into a variable that is Capitalized.
Try:
class Editor extends React.Component{
render(){
return <Renderer overrideClass={OverridenComponent}/>;
}
}
class Renderer extends React.Component{
render(){
const Component = this.props.overrideClass
return <Component importantData="TEST"/>;
}
}
class OverriddenComponent extends React.Component{
render(){
return <div>{this.props.importantData}</div>;
}
}
In addition to the marked answer above, I found that passing in a callback function which takes the props and returns the class instance to be effective as well. It looked like:
class Editor extends React.Component{
render(){
return <Renderer overrideClass={(importantData) =>
<OverridenComponent importantData={importantData}/>}
/>;
}
}
class Renderer extends React.Component{
render(){
return this.props.overrideClass("TEST");
}
}
class OverriddenComponent extends React.Component{
render(){
return <div>{this.props.importantData}</div>;
}
}
I'm not sure exactly which method is better, but his answer was closer to what I was actually asking for as far as passing a class. I suspect that his way is more flexible too.

use lifecycle in child component in react

I'm implementing an inherit action to archive my goal.
My goal is to call a lifecycle event in child component instead of parent one. That's what I can do in C# .net. How can I archive it? Is there any difference?
When I call lifecycle event in parent component, it works fine
Here's my code
class A extends React.Component {
render() {
return (
//......
)
}
}
class B extends A {
componentDidMount() {
console.log('componentDidMount') // didn't log here
}
componentDidUpdate(prevProps) {
console.log('componentDidUpdate:', prevProps) // didn't log here
}
}
Thanks all
This is quite tricky.
In JavaScript, a class cannot extend from multiple classes, which is also known as “multiple inheritance”. In JavaScript, objects can only be associated with a single prototype, and extending multiple classes would mean that an object associates with multiple prototypes, which is not possible.
Also, to have lifecycle methods, the class should extend React.Component.
So you can either extend React.Component or Component A.
Multiple inheritance doesn't allow in javascript by the time I'm writing this. And life-cycle event will work only if you extends React.Component. So, you should not extends another component in react. The recommended way is - use composition pattern instead of inheritance.
import B from './B';
class A extends React.Component {
render() {
return (
<B />
//.......
)
}
}
class B extends React.Component {
componentDidMount() {
console.log('componentDidMount')
}
componentDidUpdate(prevProps) {
console.log('componentDidUpdate:', prevProps)
}
}
Now it will work. Hope you will figure out the problem. For more please visit reactjs composition vs inheritance
the trick is to use super.componentDidMount() in the child component
componentDidMount() {
super.componentDidMount();
console.log('componentDidMount')
}
here you can find the working code
https://codesandbox.io/s/crazy-snow-1k9t2?file=/src/App.js

Type of generic abstract react component

This is my first question, please be gentle ;)
I have several components which share behavior, so I would like to have them all extend the same class, so I don't have to duplicate my functionality:
export abstract class FooComponent<P extends {}> extends React.Component<P, {}> {
foobar: Foobar = new Foobar();
}
Other classes inherit this component like:
export class BarComponent extends FooComponent<{baz?: boolean}> {
//dostuff
}
I try to pass these classes as a type into a function, like so:
setFoo (foo: typeof FooComponent) {
let obj = { foo: foo };
this.foo = <obj.foo />;
}
this.setFoo(BarComponent);
but my compiler throws the following error:
Type 'BarComponent' is not assignable to type 'FooComponent<any>'.
Property 'foobar' is missing in type 'BarComponent'.
It works if I don't extend the props, making FooComponent non-generic, but the FooComponents all have different props, which would not be type-safe if I were to set them as any.
Is there a way I can pass the type of my derived classes, and use them as my base class?
Edit
I found a way to remove all the different props in my FooComponents, so I could make it a base class without a generic type as shown below.
export abstract class FooComponent extends React.Component<{baz?: boolean}, {}> {
foobar: Foobar = new Foobar();
}
This way, the setFoo function as shown in the original question works, and no longer throws an error.
Thanks for the provided answers though, They gave me some new insights.
You can specify the constructor signature instead of using typeof
setFoo <P, T extends FooComponent<P>>(foo: new (... p: any[]) => T)
You're almost there :
React.createElement(foo, whateverProps);
should do the trick. whateverProps is an object that contains, well, props for the foo class. Be aware that by doing this, you lose some of the TypeScript advantages because the compiler won't be able to check the props against the class' props interface.
IF THE IDEAL IS TO ABSTRACT METHODS AND APPLY STATES ON THE BASIS OF ABSTRACT METHODS WITHOUT THE NEED TO RECONSTRUCT, I THINK THAT IT WILL SERVE THEM (AND IT MAY IMPLEMENT TO HIS NEED)
1 - ABSTRACT COMPONENT
import React from 'react';
/**
      * AbstractComponent
      *
      * Abstract mapper component, ie when extending this abstract component its component class
      * will have properties and auxiliary methods in order to streamline and simplify the deve
* #author Nathan C. do Nascimento <nathannascimento#nodesistemas.com.br>
*/
abstract class AbstractComponent extends React.Component<any, any>
{
protected init(states:any) {
this.changeInputVal = this.changeInputVal.bind(this);
this.state = states;
};
protected changeInputVal(e:any) {
this.setStateByKey(e.target.id, e.target.value);
};
private setStateByKey(key:any, value:any) {
this.setState({
[key] : value
});
console.log(value);
}
}
export default AbstractComponent;
1 - SO IN MY EXTENDED CLASS:
import React from 'react';
import AbstractComponent from './AbstractComponent';
export default class Teste extends AbstractComponent
{
protected constructor(props:any) {
super(props);
this.init({
inputVal : 'INITIAL STATE OF MY INPUT VAL'
});
}
render() {
return (
<div id='node-notify-app2'>
<input value={this.state.inputVal} id='inputVal' name='inputVal' onChange={this.changeInputVal} />
</div>
);
}
}
3 - AND TO FINISH IMPORT THE COMPONENT IN YOU APP.ts/tsx
File: App.tsx
import React from 'react';
import Teste from "../../temp";
/**
* Component APP
*
* #author Nathan C. do Nascimento <nathannascimento#nodesistemas.com.br>
*/
class App extends React.Component {
render() {
return (
<div id='node-notify-app'>
<Teste />
</div>
);
}
}
export default App;
4 - THIS RESULT
Now all features that added in the abstract element will be accessible to those who extend it, and through the setStateByKey method the abstract (parent) can control the state of the child, since configured in method init!

The this keyword is undefined in React base class

I have a basic React app and I'd like to put some commonly used functionality into a base component class and have all my other components inherit from that class to get access to those features. I have this:
export class BaseComponent extends React.Component {
constructor() {
super();
this.commonlyUsedMethod = this.commonlyUsedMethod.bind(this);
}
commonlyUsedMethod() {
let x = this.someValue; // <--- 'this' is undefined here
}
}
export class SomeComponent extends BaseComponent {
onButtonClick() {
super.commonlyUsedMethod();
}
render() {
return whatever;
}
}
The problem is that when I call super.commonlyUsedMethod() from the derived class, this.someValue blows up inside BaseComponent.commonlyUsedMethod() because this is undefined. I'm calling this.commonlyUsedMethod.bind(this); in the BaseComponent constructor, so I'm not sure what's going on.
First of all I (and most of the React dev community) don't recommend you to use inheritance. https://facebook.github.io/react/docs/composition-vs-inheritance.html
Most of the use cases you have you can solve it using Higher Order Components or writing functions in a JS file and importing it.
If you still want to go ahead and do this.
You need to bind the this when you attach the buttonClick listener
export class SomeComponent extends BaseComponent {
onButtonClick() {
super.commonlyUsedMethod();
}
render() {
return <div onClick={this.onButtonClick.bind(this)}>Hello</div>;
}
}
Here is the working example for it. https://www.webpackbin.com/bins/-Knp4X-n1RrHY1TIaBN-
Update: Problem was not with calling super with proper this, problem was with not binding proper this when attaching the onClick listener. Thanks #Mayank for pointing it out.
So I'm not sure if this a Good Practice™, but I can get it to work by calling this.someCommonMethod() instead of super.someCommonMethod(), like this:
export class SomeComponent extends BaseComponent {
constructor() {
super();
this.onButtonClick = this.onButtonClick.bind(this);
}
onButtonClick() {
this.commonlyUsedMethod(); <--- changed 'super' to 'this'
}
render() {
return whatever;
}
}
I'm new enough to React and ES6 not to know if this is how this should work. Any thoughts would be appreciated.

Resources