I've recently started to use Typescript in my React projects and I'm struggling to understand generics inside of function declarations and the Redux connect function.
For example if I have the following code
interface WidgetStateProps extends BasicConfiguration {
filters: Filter[]
}
class Widget extends React.Component<WidgetComponentProps, {}> {
// my component
}
Now to my understanding, by declaring the generic, <WidgetComponentProps, {}> here, we have told typescript that we expect that the props our Widget component will receive will have the properties defined in WidgetStateProps and BasicConfiguration. Correct?
Great now moving onto an example of typing the connect function which is not necessarly in the same component as the one above.
export default connect<ModalStateProps, ModalDispatchProps, ModalOwnProps>(mapStateToProps, mapDispatchToProps)(Modal);
In this connect function we have declared 3 generics. I'm confused on how these are typing mapStateToProps and mapDispatchTopProps when both of these return a function. Furthermore, what is ModalOwnProps typing?
The final things I'm having trouble understand revolves around using connect with higher order functions. Say I have the following connect function
export default function composeWidget<T extends WidgetStateProps, P extends WidgetDispatchProps, Q extends WidgetOwnProps>(Component, mapStateToProps, mapDispatchToProps = undefined, mergeProps = undefined) {
// some more code
return connect<T, P, Q>(wrappedMapStateToProps, wrappedMapDispatchToProps, mergeProps)(getComposedWidgetComponent(Component));
}
This is where everything starts to get really fuzzy. From this it seems that my first point is wrong. How could T extends WidgetStateProps define the shape of the first argument in the function which is Component when it clearly defines the second one.
Another confusion is what advantage do we gain by extending these various interfaces such as WidgetStateProps?
Related
But what is the difference between both of them ?
From this post it seems like there is no difference and it is just different way of writing.
Please provide an example to make the difference more clear.
All React Function Components are regular Javascript functions.
Not all regular Javascript functions are React Function Components.
Function components are just a signature for a specific function.
You can look at the Typescript definition to see exactly what that signature is:
interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
propTypes?: WeakValidationMap<P> | undefined;
contextTypes?: ValidationMap<any> | undefined;
defaultProps?: Partial<P> | undefined;
displayName?: string | undefined;
}
Reference: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/v17/index.d.ts#L542
And PropsWithChildren is defined as:
type PropsWithChildren<P> = P & { children?: ReactNode | undefined };
Reference: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/v17/index.d.ts#L822
The JSX parser will translate JSX and pass certain parameters to these functions.
JSX:
<CompOne someProperty="someValue"><CompTwo/></CompOne>
Equivalent to:
CompOne({someProperty: "someValue", children: CompTwo({})})
The signature is just letting you know how the JSX will be parsed, so you know how to access those parameters within your function.
The signature includes some additional info as well: the function should return a ReactElement or null, and it can have those four properties.
For example, I'm trying to log the someProperty value from CompOne:
<CompOne someProperty="someValue" someOtherProp="someOtherValue" />
CompOne(someProperty) {
console.log(someProperty); // logs {someProperty: "someValue", someOtherProp: "someOtherValue"}
return null;
}
This is incorrect, because I was not using the function as the Function Component signature describes. The JSX parser reads the properties into an object, and passes it as the first parameter to the function. Although the code will still execute, it is not what I intended to happen.
CompOne(props) {
console.log(props.someProperty); // logs "someValue"
return null;
}
This works as intended because I know the structure of a Function Component.
I have tried my best to keep it as simple as I can for your understanding:-
Javascript functions:-
function add(a, b) {
return a + b;
}
React functional component:-
import React from 'react';
const DisplayMessage = (props) => {
return <h1>{props.message}</h1>;
};
export default DisplayMessage;
USE:- JS functions are particular to do a thing. as you see in the example it will do the addition of two numbers only.while React functional components are used to define components in React that can be rendered to the UI. The display component will render the functional component.
DEFINITION:- JS functions are defined using the function keyword, while React functional components are defined using the const keyword and an arrow function.
PROPS:- We can pass and receive props to react functional components but not too regular JS functions.
STATE:- JS function doesn't have any state while React functional component when declared in classes will have the state.
RENDERING:- JS function doesn't render any change in the value.while React functional component re-render on every state or props change.
I was trying to comprehend this code on github
Here they programmer have used something like this
constructor(props) {
super(props);
this.actions = bindActionCreators(Actions, this.props.dispatch);
}
Question 1: Here, this.actions = bindActionCreators(Actions, this.props.dispatch); doesn't make sense to me
Also, This isn't primary question but from where I learned React-redux, we used to connect component like this
export default connect(mapStateToProps,
{fetchCoin,
updateCrypto,
CurrencyRate,
CurrencyState
})(cryptoTicker);
In the above code Snippet the programmer have done something like this
#connect(state => {
return {
score: state.game.get("score"),
result: state.game.get("result")
};
})
Question 2: ** Which again sort of looks alien to me (like I have few months of experience using js but this is the first time I am encountering **#) So can someone please explain me what is # in general in JS?
And lastly he have declared two functions which are being called onclick after return statement of class
_handleNewGame = () => {
this.actions.initGame();
}
/**
* Save the current game`s state.
*/
_handleSaveGame = () => {
this.actions.saveGame();
}
Now Since I am still relatively new to JS and react, I have two questions for this part
Question 3: Can we create a function inside a class after return and render? If yes then wouldn't it have been a good practise (in general) to create a function before render where all the other functions are declared?
For question #1 and #2, your '#connect' and 'connect(mapStateToProps, ...)(cryptoTicker)' syntax is equivalent. The # indicates to the parser that we're using a decorator for our function, the connect(...) function, and outputs the same class, in this case Game, but with added functionality. This is called a HoC (Higher Order Components) design pattern and you can read more about it here https://medium.com/#mappmechanic/react-utility-higher-order-components-as-decorators-tc39-stage-2-9e9f3a17688a
For question #3, you are correct, it is better practice to leave the render function for the last function in the component.
I'm converting a react project from redux to mobx, and I'm having the following problem: I was using the container/presenter pattern with redux, which meant using the redux "connect" function, like this:
export default connect(mapStateToProps, mapDispatchToProps)(Leads);
The problem I'm having is that there's no equivalent mobx function, so instead, I tried to simply create an instance of the component in the container. Something like:
render() {
return (
<MyComponent
store={mystore}
/>
);
}
Unfortunately, that doesn't work, because MyComponent has injected properties from react-router, something like this:
class MyComponent extends React.Component<ReportProps & RouteComponentProps<ReportProps>> {
constructor(public routeProps: ReportProps & RouteComponentProps<ReportProps>) {
super(routeProps);
}...
I tried getting rid of the container concept, but the same problem occurs in other places because I'm using the mobx-react #inject decorator. For example, I have a component like this:
export interface AddressProps {
report: IReportStore;
}
#inject((rootStore: RootStore) => ({
report: rootStore.report
}))
#observer
class Address extends React.Component<AddressProps> {
...
If I then try to use my component somewhere, typescript complains that I'm not passing the required property (report, in this instance), even though I shouldn't need to, since I'm injecting the properties.
I figure I must be missing something basic, as this is a fairly straightforward use of mobx. Or maybe it's just a typescript problem...? If so, any ideas how to fix or work around it?
Thanks in advance,
Jonathan
There are a lot of problems around the mobx inject method.
the original idea was to return a Partial<TProps> but you can't do this typed without losing your original Class: React.Component<Partial<TProps>,TState> != YourComponent - the set properties.
Read the discussed problem here: https://github.com/mobxjs/mobx-react/issues/256
Simplistic solution
Use optional parameters in props and set them in a getter property:
interface AppProps {
store?: SDtore;
}
class App {
get store(): TimeEntryStore {
return this.props.store as Store;
}
method(){
this.store;///
}
}
Other solution
If you want to keep your required parameters (eg: for using the component outside of mobx etc).
You can consider casting the component to React.Component<TPropsReduced,State> where TPropsReduced is a self defined interface with required props after injected.
The downsides are:
Losing type safety at casting (eg if you make mistakes/typo's in the interface properties. (can be solved by extending/subclassing interfaces.
Losing methods calls. You will no longer have typed methods on the component (eg: when you use ref={()=>}), but using this is dis-advised anyways.
Example:
interface AddressPropsMobx {
}
interface AddressProps extends AddressPropsMobx {
report: IReportStore;
}
//Pure react component
class Address extends React.Component<AddressProps> {}
// Mobx version:
const MobxAddress = inject((rootStore: RootStore) => ({
report: rootStore.report
}))(observer(Address)) as React.Component<AddressPropsMobx>; //unsafe cast
So i love this React thingy, and we have this so called 'stateless' functions to help us build a 'dumb' component. Now i want to create a class that produce a stateless function. Why you may ask, well i love the idea of inheritance and wanting to 'extend' my stateless function basic capability, said i want to add a helper function as a statics that binds to the function itself.
I ended up with this code
class Stateless {
constructor() {
return this.render.bind(this)
}
nanny() {
// do something
}
render(props) {
// yeay! a stateless function!
// plus i can access nanny by using this.nanny()
}
}
And when i extend it, i can see that the inheritance is working well.
BUT, if then i initialize the class:
const stateless = new Stateless()
Why can't i access stateless.nanny even tho inside the render function i can see that this.nanny is accessible? Where does the nanny lives? Does it binded to the render function?
EG:
class Stateless {
constructor() {
return this.render.bind(this)
}
nanny() {
console.log('foo')
return true
}
render(props) {
console.log(this.nanny()) // -> returns 'foo'
return 'JSX'
// this should return a JSX
}
}
const stateless = new Stateless() // -> stateless IS a function
stateless()
// 'foo'
// true
// JSX
stateless.nanny
// undefined
While clearly inside render when i called this, there is nanny there. But when i
refer it outside, the nanny is gone. I thought nanny should be a static property of the stateless, right?
If you are returning object from constructor - new will return that object instead of the instance of the class being constructed (more info).
Therefore line
const stateless = new Stateless()
will assign to stateless variable result of this.render.bind(this) - that is reference to method (function) of Stateless class, that is not an instance of Stateless. Therefore stateless.nanny makes no sense - as function render does not have such property defined. On the other hand calling bound render function directly - produce the expected result.
All in all - i strongly do not recommend you to return anything from constructor (unless you are dealing with some really weird requirements like controlling number of instances and such). It makes code hard to understand and maintain.
Your example should work if you remove this.render.bind(this) from your constructor.
It should also work, if you just remove return from the constructor:
constructor() {
this.render.bind(this)
}
However, you might actually be looking to create a higher order component that can enhance the component that it wraps.
Your higher order component is a function that returns a class that renders the component that it passed to it:
import React from 'react'
function HigherOrderComponent(WrappedComponent) {
return class Enhancer extends React.Component {
constructor(props) {
super(props)
}
exampleFunc() {
// Code here
}
render() {
return <WrappedComponent exampleprop={ this.exampleFunc } />
}
}
}
export default HigherOrderComponent
Then you can import HigherOrderComponent into your stateless dumb component file and wrap the export:
import React from 'react'
import HigherOrderComponent from './HigherOrderComponent'
const DumbComponent = (props) => {
// Return JSX
// You can use props.exampleprop
}
export default HigherOrderComponent(DumbComponent)
Here are some articles that you can read on higher order components:
https://facebook.github.io/react/docs/higher-order-components.html
https://medium.com/#franleplant/react-higher-order-components-in-depth-cf9032ee6c3e
I'm looking at some ES6 code and I don't understand what the # symbol does when it is placed in front of a variable. The closest thing I could find has something to do with private fields?
Code I was looking at from the redux library:
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'redux/react';
import Counter from '../components/Counter';
import * as CounterActions from '../actions/CounterActions';
#connect(state => ({
counter: state.counter
}))
export default class CounterApp extends Component {
render() {
const { counter, dispatch } = this.props;
return (
<Counter counter={counter}
{...bindActionCreators(CounterActions, dispatch)} />
);
}
}
Here is a blog post I found on the topic: https://github.com/zenparsing/es-private-fields
In this blog post all the examples are in the context of a class - what does it mean when the symbol is used within a module?
I found the accepted answer was not enough to help me sort this out, so I'm adding a little more detail to help others who find this.
The problem is that it's unclear exactly what is the decorator. The decorator in the example given is not just the # symbol, it's the #connect function. Simply put, the #connect function is decorating the CounterApp class.
And what is it doing in this case? It's connecting the state.counter value to the props of the class. Remember that in redux the connect function takes two arguments: mapStateToProps and mapDispatchToProps. In this example, it's taking only one argument - mapStateToProps.
I haven't investigated this too much, but this appears to be a way to encapsulate your state-to-props and dispatch-to-props mappings so they accompany your components rather than being located in a different file.
It's a decorator. It's a proposal to be added to ECMAScript. There are multiple ES6 and ES5 equivalent examples on: javascript-decorators.
Decorators dynamically alter the functionality of a function, method, or class without having to directly use subclasses or change the source code of the function being decorated.
They are commonly used to control access, registration, annotation.
What is #myDecorator()?
The # symbol in javascript stands for a decorator. Decorators are not present in ES6 so the in code you are working with the decorator is probably transpiled to an version of javascript which can be run in any browser.
What is a decorator?
A decorator extends (i.e. decorates) an object’s behavior dynamically. The ability to add new behavior at runtime is accomplished by a Decorator object which ‘wraps itself’ around the original object. A decorator is not just a concept in javascript. It is a design pattern used in all object oriented programming languages. Here is a definition from wikipedia:
In object-oriented programming, the decorator pattern is a design
pattern that allows behavior to be added to an individual object,
dynamically, without affecting the behavior of other objects from the
same class. The decorator pattern is often useful for adhering to the
Single Responsibility Principle, as it allows functionality to be
divided between classes with unique areas of concern
Why use a decorator?
The functionality of an object can be modified at runtime when using a decorator. For example, in your code you simply imported the decorator and added it to your CounterApp class. Now your CounterApp has dynamically added functionality Without you knowing the implementation details.
Example:
// decorator lights is a function which receives the class as an argument
let lights = function(tree) {
// The behaviour of the class is modified here
tree.treeLights = 'Christmas lights'
}
#lights // the decorator is applied here
class ChristmasTree {}
console.log(ChristmasTree.treeLights); // logs Christmas lights