How to set class default props in react 18.2.0? - reactjs

I saw some news about defaultProps being deprecated, but altenate solution I found was targeting function like component. But what about class component? I am new to react. Feeling like so many react things has change these years.
Oh I saw a another way is to use a deprecated package Prop-types, but it just don't feel right.
image here

Just use the static defaultProps property
Typescript example
class MyComponent extends React.Component<MyPropType,MyStateType> {
static defaultProps = {
/* Declare your default Props here */
};
Javascript example
class MyComponent extends React.Component {
render() {
// ...implement render method
}
}
// Set default props
MyComponent.defaultProps = {
/* Declare your default Props here */
};

yup, it will be deprecated in the future but only for functional components, for class-based components, it will stay as it is

Related

Add autocomplete to Typescript/React component

I have a component (typescript + react) which I published on NPM. I want to make IntelliSense autocomplete React props for this component for me. For plain react components I used js doc, but it doesn't work here.
example of component:
class MyComp extends React.Component<
MyCompPropsInterface,
MyCompComponentState
> {...}
index file
import { MyComp } from './components/MyComp ';
export { MyComp };
If I missed something please point it and I will add it.
So I found the problem, I didn't pass my interface to the constructor.
How it should be:
class MyComp extends React.Component<
MyCompPropsInterface,
MyCompComponentState
> {
constructor(
public props: ImagePropsInterface,
)
}

How to make components explicit in what props they accept?

Is there any known practice to make a React component constructor explicit in what arguments it accepts?
Looking at a component like below, I cannot immediately tell what do I need to pass to the constructor to initialize the component.
Instead, I need to search for specific props in the component body or check how has the component been initialized previously (if it has).
class MenuItem extends React.Component {
constructor(props) {
super(props)
}
render() {
return <div name={this.props.name}></div>
}
}
I would need something like:
class MenuItem extends React.Component {
constructor(name) {...
You can explicitly show what props your component accepts, including their types.
MenuItem.propTypes = {
name: PropTypes.string // optional string
};
You can even define them as required:
MenuItem.propTypes = {
name: PropTypes.string.isRequired // required string
};
Be sure to import the library:
import PropTypes from 'prop-types';
More information in the react docs
There is several options to type your props.
The first one is React PropTypes, it works like this:
import PropTypes from 'prop-types';
class MenuItem extends React.Component {
constructor(props) {
super(props)
}
render() {
return <div name={this.props.name}></div>
}
}
MenuItem.propTypes = {
name: PropTypes.string.isRequired
}
You just have to write the name and types of your props inside an attribute "propTypes" of your component class.
React PropTypes is a good solution when you want to type your component props.
https://reactjs.org/docs/typechecking-with-proptypes.html#proptypes
There is another solution, a Javascript Flavor like Typescript.
After setting up Typescript on your React app, you can use Typescript with your component like this:
interface IMenuItem {
name: string;
}
class MenuItem extends React.Component<IMenuItem> {
constructor(props) {
super(props)
}
render() {
return <div name={this.props.name}></div>
}
}
The advantage with Typescript is that you can type every variable, every state, every props, everything !
However, this solution is expensive in time because you have to learn well Typescript and you have to type correctly every piece of your app.
https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html
Finally, if you just want your IDE to tells you what props you can use without typing them, you can just use object destructuring on your props with a Functional Component like this:
const MenuItem = ({name}) => (
<div>{name}</div>
)
Hope this will help !
If your concerns are mainly about visibility you may be better off only writing functional components which is possible since hooks do not require any class components anymore:
const MenuItem = ({name}) => (
<div>{name}</div>
)
Buy destructuring the props in the argument list you can easily see which props are being used immediately just by looking at the function definition. From my experience writing 100's of components, functional components are usually more concise, easier to grasp and reduce boilerplate code.
Apart from that javascript is still a scripting language which means anything can be passed at runtime. PropTypes or using typescript may help you with auto-completion and type checking.

How to solve TypeScript typing issue with component composition

React promotes composition over inheritance, but I
I have a React component in TypeScript that should host certain kinds of React components. For example, let's say I have a MenuBar component, and it takes an array of various MenuBarItem components it can host as a prop. I want to force all menu bar items to have the same root element structure, so they must be rendering the MenuBarItem component at the root.
The problem I have is that, if I was using inheritance, I can achieve this by defining the prop as something like items: MenuBarItem[], but I cannot figure this out how to enforce this with composition.
By using composition, I created FooMenuBarItem and BarMenuBarItem, and let them render the MenuBarItem internally (See below). So, they don't share the common base class that I can use as a type.
How would I solve this typing problem with composition?
export class MenuBarItem extends React.Component<{}, {}> {
render() { return /*...*/; }
}
export class FooMenuBarItem extends React.Component<{}, {}> {
render() { return <MenuBarItem>Foo</MenuBarItem>;}
}
export class BarMenuBarItem extends React.Component<{}, {}> {
render() { return <MenuBarItem>Bar</MenuBarItem>;}
}
export interface MenuBarProps {
items: MenuBarItem[]; // This would only work if I use inheritance to get the common base type!
}
export class MenuBar extends React.Component<MenuBarProps , {}> {
render() {
<div>{this.props.menuBarItems}</div>
}
}
I found a similar question here, but with no answers.
I think the short answer is that there is no way to declare the exact type you want (I would be interested to hear otherwise!).
To be honest I would normally just go with:
export interface MenuBarProps {
items: React.ReactNode;
}
And rely on consumers of the code to do the sensible thing.
The only other thing I would consider is that perhaps you could use:
export interface MenuBarProps {
items: React.Component<MenuItemProps>;
}
This would only make sense if the various different menu item components all shared a set of common props.

In reactjs, what is wrappedComponent.propTypes?

Below code example is a simplified version a component. I don't understand the code at the bottom of this component, the Case.wrappedComponent.propTypes part. I can't find relevant document about wrappedComponent on Internet as well.
Questions:
What is wrappedComponent and propTypes key in it?
What do they do?
Where can I find document for these things?
import React, { Component } from 'react';
#inject('store') #observer
export default class Case extends Component {
constructor(props) {
super(props);
this.caseId = this.props.match.params.id;
this.setOtherComment = this.setOtherComment.bind(this)
this.submitOtherComment = this.submitOtherComment.bind(this)
}
render() {
return '...'
}
}
Case.wrappedComponent.propTypes = {
store: React.PropTypes.object.isRequired,
match: React.PropTypes.object.isRequired
};
This is an API of mobx-react (with inject) and according to the DOCS
Using propTypes and defaultProps and other static properties in combination with inject
Inject wraps a new component around the component you pass into it. This means that assigning a static property to the resulting component, will be applied to the HoC, and not to the original component
........
if you want to make assertions on the data that is being injected
(either stores or data resulting from a mapper function), the
propTypes should be defined on the wrapped component. Which is
available through the static property wrappedComponent on the inject
component

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