Last updated on June 28, 2020

Typescript with React: Components

👋 Hello! Most of these notes are "knowledge in the making", so parts of them could be incomplete 🙈, inaccurate 🙉 or even potentially wrong 🙊.

This is the way I'm currently declaring components when working with TypeScript and React.

To define a React.FunctionComponent<> connected to Redux using hooks:

interface IProps {
  title: string;
}

export const MyComponent: React.FunctionComponent<IProps> = ({
  title
}) => {
  const [content, setContent] = useState(null);
  const comments = useSelector((state: TAppState) => state.comments);
  const dispatch = useDispatch();

  return (
    <button onClick={() => dispatch(doSomething())}>Save</button>
  );
};

To define a React.Component<> connected to Redux with properties and state:

// updateTitle is a function defined in a separate file
interface IProps {
  updateTitle: typeof updateTitle;
  title: string;
}

interface IState {
  // ...
}

class MyComponent extends React.Component<IProps, IState> {
  constructor(props: IProps) {
    super(props);

    this.state = { /* ... */ };

    this.onClick = this.onClick.bind(this);
  }

  onClick() {
    this.props.updateTitle("Updated title!");
  }

  render() {
    return (
      <div>
        <span>{this.props.title}</span>
      </div>
    );
  }
}

// TAppState should be replaced by the type of the global state
function mapStateToProps(state: TAppState) {
  return {
    title: state.title
  };
}

// TAction should be replaced with the type grouping the actions that can be
// bound
function mapDispatchToProps(dispatch: ThunkDispatch<any, any, TActions>) {
  return bindActionCreators(
    {
      updateTitle
    },
    dispatch
  );
}

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

Conventions

  • Methods that are meant to handle events should:
    • Start with on (e.g. onSaveButtonClick).
    • Be bound in the constructor to this, to avoid the arrow functions inside render().