React render props pattern class errors


React render props pattern class errors



Help please.
it is assumed that the component can be used like this:


<MouseCoordinates></MouseCoordinates>

or

<MouseCoordinates>
{(x,y) => { ... }}
</MouseCoordinates>



I don't understand what does it want.
Here is the code:


import React, { MouseEvent } from 'react';

const initialState = { x: 0, y: 0 };
const defaultProps = {
children: (args: TMouseCoordinates) => null,
};

type TMouseCoordinates = typeof initialState;
type TDefaultProps = typeof defaultProps;

type TState = Readonly<TMouseCoordinates>;
type TProps = Partial<
{
children?: (coordinates: TMouseCoordinates) => JSX.Element;
} & TDefaultProps
>;

class MouseCoordinates extends React.Component<TProps, TState> {
static readonly defaultProps: TProps = defaultProps;
^^^^^^^^^^^^

readonly state: TMouseCoordinates = initialState;

componentDidMount() {
document.addEventListener('mousemove', this.handleMouseMove);
^^^^^^^^^^^^^^^^^^^^
}

componentWillUnmount() {
document.removeEventListener('mousemove', this.handleMouseMove);
^^^^^^^^^^^^^^^^^^^^
}

handleMouseMove = (event: MouseEvent<HTMLElement>): void => {
const { screenX = 0, screenY = 0 } = event;

this.setState(() => ({
x: screenX,
y: screenY,
}));
};

render() {
const { children } = this.props;
const isRenderIsFunction = typeof this.props.children === 'function';

return isRenderIsFunction ? children(this.state) : null;
^^^^^^^^^^^^^^^^^^^^
}
}



I have strange errors at:


static readonly defaultProps: TProps = defaultProps;



Type '{ children: (args: { x: number; y: number; }) => null; }' is not
assignable to type 'Partial<{ children?: ((coordinates: { x: number;
y: number; }) => Element) | undefined; } & { chi...'. Types of
property 'children' are incompatible.
Type '(args: { x: number; y: number; }) => null' is not assignable to type '(((coordinates: { x: number; y: number; }) => Element) &
((args: { x: number; y: number; }) => nu...'.
Type '(args: { x: number; y: number; }) => null' is not assignable to type '((coordinates: { x: number; y: number; }) =>
Element) & ((args: { x: number; y: number; }) => null)'.
Type '(args: { x: number; y: number; }) => null' is not assignable to type '(coordinates: { x: number; y: number; }) =>
Element'.
Type 'null' is not assignable to type 'Element'.



here is cryptic error at:


document.addEventListener('mousemove', this.handleMouseMove);



"Argument of type '(event: MouseEvent) => void' is not
assignable to parameter of type
'EventListenerOrEventListenerObject'.n Type '(event:
MouseEvent) => void' is not assignable to type
'EventListenerObject'.n Property 'handleEvent' is missing in type
'(event: MouseEvent) => void'.",



and last


return isRenderIsFunction ? children(this.state) : null;



Cannot invoke an object which is possibly 'undefined'.





What were you trying to do? What did you expect? Is this your own code or just code you've picked up from somewhere and tried to use (i.e. why is there code with ~3 independent errors in code you're writing)? Also, try to fix the title. everyone here is seeking help and tech belongs in the tags.
– Damien_The_Unbeliever
Jul 1 at 15:40





in defaultProps you have children as function returning null. In TProps you declare that children, if present, must also be a function that returns JSX.Element. But in reality it can't be both - that's what the first error is about.
– artem
Jul 1 at 15:44


defaultProps


children


null


TProps


children


JSX.Element





@artem but React.Element - it's a subset that includes null
– Vadim
Jul 1 at 15:47





The third error tells me that you are compiling with strictNullChecks turned on, if so then null as well as undefined values are excluded from every type.
– artem
Jul 1 at 16:01


strictNullChecks


null


undefined




3 Answers
3


type TProps = Partial<
{
children?: (coordinates: TMouseCoordinates) => JSX.Element;
} & {
children: (args: TMouseCoordinates) => null,
}>;



so you simple say: children props is required and not and contain both functions: (args: TMouseCoordinates) => null and (coordinates: TMouseCoordinates) => JSX.Element its simple has no sense.


children


(args: TMouseCoordinates) => null


(coordinates: TMouseCoordinates) => JSX.Element



i guess this is the interface you need:


interface Props{
children?: (args: TMouseCoordinates) => (JSX.Element | null)
}





but I use to declare default props as it has been decsribed in doc
– Vadim
Jul 1 at 15:50





I'm not a novice in typing - I used Flow, but typescript's dances at default props is a little bit confusing
– Vadim
Jul 1 at 15:54






as described in docs default props should be declared in interface as optional and in defaultProps type it should be declared as required If developer does not describe children in the component - component should not do anything -> render null. But if children function is present - it should produce JSX.Element In general - it's an option
– Vadim
Jul 1 at 16:21






I want to have children function optional, but have defaultProps.children to be present in case developer does not describe children function
– Vadim
Jul 1 at 16:29






so, how to in this case should I describe optional children prop?
– Vadim
Jul 1 at 16:37



MouseEvent should not be imported from React


MouseEvent



Here is the correct code:


import React from 'react';

export type TMouseEventRenderer = (coordinates: ICoordinates) => JSX.Element | null;

const initialState = { x: 0, y: 0 };
const defaultProps = {
children: (() => null) as TMouseEventRenderer,
};

type TDefaultProps = typeof defaultProps;
type TProps = Readonly<{ children?: TMouseEventRenderer } & TDefaultProps>;
type TState = Readonly<ICoordinates>;

class MouseCoordinates extends React.Component<TProps, TState> {
static readonly defaultProps: TDefaultProps = defaultProps;
readonly state: TState = initialState;

componentDidMount() {
document.addEventListener('mousemove', this.handleMouseMove);
}

componentWillUnmount() {
document.removeEventListener('mousemove', this.handleMouseMove);
}

handleMouseMove = (event: MouseEvent): void => {
const { screenX = 0, screenY = 0 } = event;

window.requestAnimationFrame(() => {
this.setState(() => ({
x: screenX,
y: screenY,
}));
});
};

render() {
const { children } = this.props;
const isRenderIsFunction = typeof this.props.children === 'function';

return isRenderIsFunction ? children(this.state) : null;
}
}






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

How to make file upload 'Required' in Contact Form 7?

Rothschild family

amazon EC2 - How to make wp-config.php to writable?