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

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.

Related

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.

redefine componentWillReceiveProps in external component

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

Manually instantiating ReactNative components?

It seems like that in ReactNative that you can do something like new SomeComponent(props) and return someComponent.render(). I'm guessing this is basically what the JSX does when you directly declare <SomeComponent someProp="etc"/>? If that's the case, is there any potential downsides to manually manipulating the components rather than using JSX?
It seems like that in ReactNative that you can do something like new
SomeComponent(props) and return someComponent.render()
Not really. If you manually instantiate a component class, among other things lifecycle methods (componentWillMount(), componentDidMount()) won't work.
I'm guessing this is basically what the JSX does when you directly
declare
Have a look at what babel compiles to, but basically JSX compiles down to plain js:
class Hello extends React.Component {
render() {
return <div>Hello {this.props.toWhat}</div>;
}
}
translates to:
class Hello extends React.Component {
render() {
return React.createElement('div', null, `Hello ${this.props.toWhat}`);
}
}
If that's the case, is there any potential downsides to manually
manipulating the components rather than using JSX
You could use React.createElement and completely avoid JSX, but in my experience this is harder and more verbose. Manually instantiating components though like you initially suggested defeats the purpose of using React :)
Some good links which go in more detail:
https://reactjs.org/docs/react-without-jsx.html
https://reactjs.org/docs/react-component.html

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