redefine componentWillReceiveProps in external component - reactjs

I have a module:
import {ReferenceInputController} from 'ra-core'
I need to redefine it's componentWillReceiveProps, but I don't want to copy entire component and make it custom. Is there a more easy way to redefine it? Something like creating a new component which extends the ReferenceInputController etc ... ?

Assuming ReferenceInputController extends React.Component, then you should be able to achieve this using regular class inheritance.
To illustrate this, consider the following Foo class.
Here you can see that it extends the base class ReferenceInputController, while also providing custom logic for componentWillReceiveProps. This custom logic will be used in place of the equivalent componentWillReceiveProps method that was defined in ReferenceInputController:
class Foo extends ReferenceInputController {
/*
Redefinition of componentWillReceiveProps logic for Foo extension
of ReferenceInputController base class goes here
*/
componentWillReceiveProps(nextProps) {
console.log('Custom logic for Foo that is run during componentWillReceiveProps');
}
/*
The render method defined in your ReferenceInputController base class, as well as
any other component lifecycle methods defined in ReferenceInputController will be
invoked when Foo is rendered
render() {
...
}
*/
}
You would then use (or render) Foo just as you would use ReferenceInputController:
<div>
<Foo ... />
</div>
Here is a jsFiddle if you'd like to see this in action

Related

How to use noImplicitOverride flag from TS4.3 with React class components

I've updated TS to 4.3 and tried to add flag noImplicitOverride to my tsconfig.json.
I've got a lot of issues related to overriding inside my React class components ie. render()
Is it some approach to use this flag with React?
To fix the error, add the override keyword before any methods that override the method from the base class:
class Foo extends React.Component {
override render() {
return <p>Hello, world!</p>
}
}
Note that this is not React-specific and applies in general to all classes that extend another class.
See the reference on noImplicitOverride for more information.
Alternatively, if you don’t to add override before each render(), you could use functional components instead with hooks.

Using class member as a type

I want to tell Typescript that one member of one of my class is coming from another class.
For example:
Class Main{
getDataFromChild(data){
console.log(data)
}
}
Class Child{
getDataFromChild: Main.getDataFromChild //<== something like this
}
Use Case
My use case is React parent passing method down to React child. I want my IDE to navigate to Parent method decleration when I click on the passed method inside child.
export default class Parent extends Component {
simplifiedFunction (value) { // Line A
console.log(value)
}
render () {
return (
<div>
<Child
simplifiedFunction = {this.simplifiedFunction}
/>
</div>
)
}
}
export default class Child extends Component {
render () {
return (
<div>
<h1 onClick= { () =>
this.props.simplifiedFunction(<SomethingThatYouWantToPassIn>)//<== ctrl + click on simplifiedFunction should take me to its definition in parent class (Line A)
}
> Something</h1>
</div>
)
}
}
You could define an interface (named or anonymous):
interface SharedFeature {
sharedFunction: () => void;
}
and then implement it on the parent
class Parent extends React.Component implements SharedFeature {
sharedFunction() { ... }
render() { return <Child sharedFunction={sharedFunction} />; }
}
finally you can use the interface as part of the Child component's props
class Child extends React.Component<SharedFeature, {}> {
render() {
return <div>
{this.props.sharedFunction()}
</div>;
}
}
When using Component class you can take advantage of it's two generic arguments, first one defined the interface of props and the second one defines interface of the state. You can either use SharedFeature interface directly or extend another interface by it and then use that interface for props.
I dont know what kind of IDE you use but usually in this case when you do "Go to implementation" the IDE should succesfuly locate class Parent as it implements the interface that defines the function sharedFunction();
Beware that if you do "Go to definition" you WILL be taken to the declaration of the interface SharedFeature. If you want to use "Go to definition" nontheless (antipattern)use the class Parent itself as type for class Child's props. However this also makes Parent's method render() and ANY OTHER MEMBERS part of the props aswell.
I don't think this will work the way you are hoping it will. Namely your <Child/> component shouldn't have any awareness as to what passed it the simplifiedFunction prop. In your case, you happen to be passing it in from <Parent/>, but you should be able to pass in any function that satisfies the contract of the function. Imagine you had 3 other components that passed in different functions, your child component should never have to care about that.
Your question says that you "want to tell Typescript that one member of one of my class is coming from another class." This is an XY problem, in the sense that you say you want to do one thing (copy a method from one class to another) but your goal is something else (passing a method to a React component), and this should be done a different way.
Luk's answer gives a good solution for your actual use case. In my answer I'll address the original question about copying a method from one class to another, and explain why doing that is not a good solution.
Strictly speaking, the answer is simple:
class Main {
foo(): void {
console.log('bar');
}
}
class Child {
foo = Main.prototype.foo;
}
However, do not do this. You will be arrested by the OOP police, and sent to OOP jail.
It almost always doesn't make sense to do this. A method on the class Main may make use of properties that are defined in that class. Child is not a subclass of Main so it does not necessarily have the same properties. What if it's like this?
class Main {
x: string = 'bar';
foo(): void {
console.log(this.x);
}
}
class Child {
foo = Main.prototype.foo;
}
Now what is new Child().foo() supposed to do? A Child has no x property to log.
If the foo method really doesn't access any of Main's properties, and this fact is part of Main's contract (as depended on in the Child class), then the method should be static and the Child class should invoke it as Main.foo().
If the foo method does access some of Main's properties, but only properties shared by the Child class, then you should design your class hierarchy so that either Child is a subclass of Main, or so that those properties and the foo method belong to a common superclass, so that they can be shared by inheritance.

Abstract component vs. prop passing

I am building an app for posting tutorials. Two of the components I have are EditTutorialForm and NewTutorialForm. These two components are essentially the same except for the methods componentDidMount and onSubmit.
What seems to make the most sense is to have an abstract component type called TutorialForm and to extend it to make EditTutorialForm and NewTutorialForm.
I have read on the React docs that inheritance is not recommended with React. Would it be "better" to pass the componentDidMount and onSubmit functions as props to the TutorialForm component, as opposed to extending the component itself?
I would create one component and check within something like the following:
For a new tutorial
<TutorialForm edit={false}>
To edit a tutorial
<TutorialForm edit={true}>
And in TutorialForm
class TutorialForm extends Component{
componentDiMount() {
this.props.edit ? do edit stuff... : do new stuff
}
submitForm = () {
this.props.edit ? submit edit... : submit new
}
}

Why do some developers use constructor and super in their class in React.js?

I always use this expression in my components:
class Cart extends Component { }
Recently I have seen a lot of codes using this expression.
class Cart extends React.Component {
constructor(props) {
super(props);
}
}
Why is it? What is the purpose of using constructor and super?
Is React.Component and Component same?
Why do we pass props in constructor and super?
I am not asking what super and constructor are, I am asking difference between 2 codes above and benefits of using each one?
I checked online but did not see any explanation, just code examples.
Constructors and super are not react specific or even javascript specific. They are specific to the inheritance in OOP.
Constructors
Constructors are what can be called as initializing functions in a class. Let's look at an example where a constructor can be used.
class parentClass {
constructor(){
this.foo = foo;
this.bar = bar;
}
function sharedMethod1(){
print(this.foo);
}
function sharedMethod(){
print(this.bar)
}
}
object1 = new ParentClass(foo1, bar1);
object1.sharedMethod1() // this will print foo1;
object1.sharedMethod2() // this will print bar1;
object2 = new ParentClass(foo2, bar2);
object2.sharedMethod1() // this will print foo2;
object2.sharedMethod2() // this will print bar2;
when there is a need to create multiple instances of a class with different values for member variables / functions, we make use of the constructor functions.
Super
The super keyword is used in inheritance as well. In inheritance when extending a child class from a parent class, there is a need to initialise the constructor of the parent class. The super keyword is used for this purpose. let's look at the below example for super.
class ParentClass (){
constructor(){
this.foo = foo;
}
}
class childClass extends ParentClass(){
super(foo1); // super is used here initialize the constructor of the ParentClass
}
The same principle mentioned above is followed in React as well.
Please look into dan abramov's blog post on constructor and super here https://overreacted.io/why-do-we-write-super-props/
Dan Abramov mentions on his blog that:
You can’t use this in a constructor until after you’ve
called the parent constructor.
JavaScript won’t let you.
JavaScript enforces that if you want to use this in a constructor, you
have to call super first.
calling super(props) is needed in order to access this.props.
as mentioned on this thread, there are 2 main reasons to use a constructor on a react component:
Initializing local state by assigning an object to this.state.
Binding
event handler methods to an instance.
If you don’t initialize state and you don’t bind methods, you don’t need to implement a constructor for your React component.
If you don’t initialize state and you don’t bind methods, you don’t
need to implement a constructor for your React component.
Copied from reactJS website.
If you don’t initialize state and you don’t bind methods, you don’t
need to implement a constructor for your React component.
The constructor for a React component is called before it is mounted.
When implementing the constructor for a React.Component subclass, you
should call super(props) before any other statement. Otherwise,
this.props will be undefined in the constructor, which can lead to
bugs.
Typically, in React constructors are only used for two purposes:
Initializing local state by assigning an object to this.state.
Binding event handler methods to an instance.
You should not call setState() in the constructor(). Instead, if your
component needs to use local state, assign the initial state to
this.state directly in the constructor:
Constructor is the only place where you should assign this.state
directly. In all other methods, you need to use this.setState()
instead.
Avoid introducing any side-effects or subscriptions in the
constructor. For those use cases, use componentDidMount() instead.
https://reactjs.org/docs/react-component.html
And here is the purpose of super() ,
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
I tried with babel, Here's what I get.
With Constructor I get this function,
class App extends React.Component{
constructor(props){
this.state = {}
}
}
Related part in ES5,
var App =
/*#__PURE__*/
function (_React$Component) {
_inherits(App, _React$Component);
function App(props) {
var _this;
_classCallCheck(this, App);
_this.state = {};
return _possibleConstructorReturn(_this);
}
return App;
}(React.Component);
Without Constructor
class App extends React.Component{
state = {}
}
ES5 code
var App =
/*#__PURE__*/
function (_React$Component) {
_inherits(App, _React$Component);
function App() {
var _getPrototypeOf2;
var _temp, _this;
_classCallCheck(this, App);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _possibleConstructorReturn(_this, (_temp = _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(App)).call.apply(_getPrototypeOf2, [this].concat(args))), _this.state = {}, _temp));
}
return App;
}(React.Component);
Why is it? What is the purpose of using constructor and super?
Constructors and the super-keyword are not react specific, but JavaScript specific. Search for inheritance and "OOP" in JavaScript to better understand it (e.g. this medium article). super and inheritance is also not only bound to JavaScript, many other languages also use it and explain it accordingly, here for example is a good explanation of how the super-keyword should be used in java.
Why do we pass props in constructor and super?
Check Why Do We Write super(props)?.
Is React.Component and Component same?
Yes. In the head-section of the files are a bunch of import ...-statements. For React.Component you will find something like import * as React from "react" or import React from "react". In case of Component you will find import { Component } from "react". Check the import-documentation from MDN for more information.
I am asking difference between 2 codes above and benefits of using each one?
There is no difference in the result. Both versions work the same and there is no (notable) difference in performance. One version is shorter and less noisy. If you have no further instructions in the constructor, I would recommend suppressing it.

In componentDidUpdate refs is undefined

I want to use Chart.js on my website. As you can see title, I'm using React.js. To use Chart.js, I need the canvas and context like this:
let context = document.getElementById('canvas').getContext('2d');
let chart = new Chart(context, ...);
so I design the component like this:
export function updateChart() {
let context = this.refs.chart.getContext('2d');
let chart = new Chart(context ,... );
...
}
export default class GraphChart extends React.Component {
constructor() {
super();
updateChart = updateChart.bind(this);
}
componentDidMount() {
updateChart();
}
render() {
return <canvas ref="chart" className="chart"></canvas>;
}
}
as you can see, I exported two things, update chart function and GraphChart class. Both will using in parent component like this:
import { updateChart } from './GraphChart';
import GraphChart from './GraphChart';
class Graph extends React.Component {
...
someKindOfAction() {
// update chart from here!
updateChart();
}
render() {
return (
<div>
<SomeOtherComponents />
<GraphChart />
</div>
);
}
}
then Parent class using exported updateChart function to update chart directly. It was working, but only first time. After unmount and mount the GraphChart component, it's refs are just empty.
Why refs is empty? And If I did wrong way, how can I get canvas context for initialize Chart.js?
Object refs is undefined, because this is not what you think it is. Try logging it.
The function you’re exporting is not bound to this of your component. Or perhaps it is, but to the last created instance of your component. You can never be sure that’s the mounted instance. And even if you are, you can not use multiple instances at the same time. So, I would dismiss this approach entirely.
Other than that, providing the function to alter some component’s state is exactly the opposite of what’s React is trying to accomplish. The very basic idea is that the component should know to render itself given some properties.
The problem you are trying to solve lies in the nature of Canvas API, which is procedural. Your goal is to bridge the gap between declarative (React) and procedural (Canvas) code.
There are some libraries which do exactly that. Have you tried react-chartjs? https://github.com/reactjs/react-chartjs
Anyways, if you’re wondering how the hell should you implement it the “React way”, the key is to declare properties your component handles (not necessarily, but preferably), and then to use component lifecycle methods (e.g. componentWillReceiveProps and others) to detect when properties change and act accordingly (perform changes to the canvas).
Hope this helps! Good luck!

Resources