the use of stateful reactive classes in typescipt

My personal opinion is that you should convert HeaderBar to a function component. The reason that it needs to be a class right now is so you can use a ref to call a class method to modify the buttons. But this is not a good design to begin with. Refs should be avoided in cases where you can use props instead. In this case, you can pass down the buttons as a prop. I think the cleanest way to pass them down is by using the special children prop.

Let’s create a BarButton component to externalize the rendering of each button. This is basically your this.state.barButtons.forEach callback, but we are moving it outside of the HeaderBar component to keep our code flexible since the button doesn’t depend on the HeaderBar (the header bar depends on the buttons).

What is a bar button and what does it need? It needs to have a label text and a callback function which we will call on click. I also allowed it to pass through any valid props of the material-ui Button component. Note that we could have used children instead of label and that’s just down to personal preference.

You defined your ButtonState as a callback which takes the HTMLButtonElement as a prop, but none of the buttons shown here use this prop at all. But I did leave this be to keep your options open so that you have the possibility of using the button in the callback if you need it. Using e.currentTarget instead of gets the right type for the element.

import Button, {ButtonProps as MaterialButtonProps} from "@material-ui/core/Button";

type ButtonState = (button: HTMLButtonElement) => void;

type BarButtonProps = {
  label: string;
  callback: ButtonState;
} & Omit<MaterialButtonProps, 'onClick'>

const BarButton = ({ label, callback, ...props }: BarButtonProps) => {
  return (
      color="inherit" // place first so it can be overwritten by props
      onClick={(e) => callback(e.currentTarget)}

Our HeaderBar becomes a lot simpler. We need to render the home page button, and the rest of the buttons will come from props.childen. If we define the type of HeaderBar as FunctionComponent that includes children in the props (through a PropsWithChildren<T> type which you can also use directly).

Since it’s now a function component, we can get the CSS classes from a material-ui hook.

const useStyles = makeStyles({
  root: {
    flexGrow: 1
  menuButton: {
    marginRight: 0
  title: {
    flexGrow: 1

const HeaderBar: FunctionComponent = ({ children }) => {

  const classes = useStyles();

  return (
    <div className={classes.root}>
      <AppBar position="static">
          <HeaderMenu classes={classes} />
          <Typography variant="h6" className={classes.title}>
              callback={() => renderModule(<HomePage />)}
              style={{ color: "white" }}
              label="Sundt Memes"

Nothing up to this point has used state at all, BarButton and HeaderBar are purely for rendering. But we do need to determine whether to display “Log In” or “Log Out” based on the current login state.

I had said in my comment that the buttons would need to be stateful in the Layout component, but in fact we can just use state to store an isLoggedIn boolean flag which we get from the response of AuthVerifier (this could be made into its own hook). We decide which buttons to show based on this isLoggedIn state.

I don’t know what this handle prop is all about, so I haven’t optimized this at all. If this is tied to renderModule, we could use a state in Layout to store the contents, and pass down a setContents method to be called by the buttons instead of renderModule.

interface LayoutProp {
  handle: ReactElement<any, any>;

export default function Layout(props: LayoutProp) {
  // use a state to respond to an asynchronous response from AuthVerifier
  // could start with a third state of null or undefined when we haven't gotten a response yet
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  // You might want to put this inside a useEffect but I'm not sure when this
  // needs to be re-run. On every re-render or just once?
  AuthVerifier.verifySession((res) => setIsLoggedIn(res._isAuthenticated));

  return (
        {isLoggedIn ? (
            label="Log Out"
            callback={() => new CookieManager("session").setCookie("")}
        ) : (
              label="Log In"
              callback={() => renderModule(<LogInPage />)}
              label="Sign Up"
              callback={() => renderModule(<SignUpPage />)}

I believe that this rewrite will allow you to use the material-ui styles that you want as well as improving code style, but I haven’t actually been able to test it since it relies on so many other pieces of your app. So let me know if you have issues.

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top