0
votes

First, I'm relatively new to the react world having coded largely APIs for the majority of my career. I'm building a react application for a non-profit and I'm just trying to get off of the ground.

I've added a header class as follows:

import './header.css';
import * as React from 'react';
import * as actions from '../../actions/authenticationActions';
import { AppState } from '../../state/appState';
import { connect, Dispatch } from 'react-redux';

const logo = require('./logo.svg');

interface Props {
    displayName: string;
    isAuthenticated: boolean;
    logIn?: () => void;
    logOut?: () => void;
}

interface State {

}
class Header extends React.Component<Props, State> {
    constructor(props: Props, state: State) {
        super(props, state);
    }

    render() {
        return (
            <div className={'Header'}>
                <div className={'Container'}>
                    <img src={logo} className="App-logo" alt="logo" />
                    <div className={'Header__nav'}>
                        <div className={'userLogin'}>
                            <div className={'user'}>{this.props.displayName}</div>
                            <a onClick={this.props.logOut}>Log Out</a><a onClick={this.props.logIn}>Log In</a>
                        </div>
                        {/*<a href='https://localhost/' className={'button button--goBack'}>Back to Website</a>*/}
                    </div>
                </div>
            </div>
        );
    }
}

export const mapStateToProps = ({ currentUser }: AppState) => ({
    displayName: (currentUser != null ? currentUser.preferredName : 'Please Log In'),
    isAuthenticated: currentUser != null
});

export const mapDispatchToProps = (dispatch: Dispatch<actions.AuthenticationActions>) => ({
    logIn: () => dispatch(actions.logIn()),
    logOut: () => dispatch(actions.logOut())
});

export default connect(mapStateToProps, mapDispatchToProps)(Header);

This largely seems to be fine, but it doesn't compile because of this error message:

Argument of type 'typeof Header' is not assignable to parameter of type 'ComponentType<{ displayName: string; isAuthenticated: boolean; } & { logIn: () => LogIn; logOut: ...'. Type 'typeof Header' is not assignable to type 'StatelessComponent<{ displayName: string; isAuthenticated: boolean; } & { logIn: () => LogIn; log...'. Type 'typeof Header' provides no match for the signature '(props: { displayName: string; isAuthenticated: boolean; } & { logIn: () => LogIn; logOut: () => LogOut; } & { children?: ReactNode; }, context?: any): ReactElement | null'.

I've battled with this for several hours now to no avail. I'm fairly confident this is a noob mistake; please be gentle!

2

2 Answers

0
votes

The error makes it seem like connect is really, really expecting a Stateless Component (although I'm not sure why). You could try:

import './header.css';
import * as React from 'react';
import * as actions from '../../actions/authenticationActions';
import { AppState } from '../../state/appState';
import { connect, Dispatch } from 'react-redux';

const logo = require('./logo.svg');

interface Props {
  displayName: string;
  isAuthenticated: boolean;
  logIn?: () => void;
  logOut?: () => void;
}

const Header = (props: Props) => (
  <div className={'Header'}>
    <div className={'Container'}>
      <img src={logo} className="App-logo" alt="logo"/>
      <div className={'Header__nav'}>
        <div className={'userLogin'}>
          <div className={'user'}>{props.displayName}</div>
          <a onClick={props.logOut}>Log Out</a><a onClick={props.logIn}>Log In</a>
        </div>
        {/*<a href='https://localhost/' className={'button button--goBack'}>Back to Website</a>*/}
      </div>
    </div>
  </div>
);

export const mapStateToProps = ({currentUser}: AppState) => ({
  displayName: (currentUser != null ? currentUser.preferredName : 'Please Log In'),
  isAuthenticated: currentUser != null
});

export const mapDispatchToProps = (dispatch: Dispatch<actions.AuthenticationActions>) => ({
  logIn: () => dispatch(actions.logIn()),
  logOut: () => dispatch(actions.logOut())
});

export default connect(mapStateToProps, mapDispatchToProps)(Header);
3
votes

The second argument in the constructor is not State, it is context.

Header is not a valid React.Component because the constructor should be

constructor(props: Props, context) {
    super(props, context);
}

or just

constructor(props: Props) {
    super(props);
}

unless you need context for something.

That said, you have typed it correctly with React.Component<Props, State>, because those two types are what are expected for the generic React.Component type, but those two types do NOT reflect what the constructor parameters should be (which is props and (optionally) context)