Home > Back-end >  TypeError: Cannot read properties of undefined (reading 'toString')
TypeError: Cannot read properties of undefined (reading 'toString')

Time:12-29

I am trying to do an onClick event in a react Modal. When I fire the onClick event I would like for it to issue a component form. The onClick event seems to work, but when it renders the component it is throwing the following error.

TypeError: Cannot read properties of undefined (reading 'toString')

Which seems to be coming from the following line in the Component Form

const page = parseInt(router.query.page.toString());

I have placed the code below for inspection

Modal:

import React, {useState} from 'react';
import { observer } from 'mobx-react-lite'
import { useDataStore } from 'stores/data';
import Space from './Space';
import { Plus } from 'components/Icons'
import ShowNetworkInfo from '../../components/Forms/ShowNetworkInfo';
import SpaceDirectory, { Header, Title, Options, Option, OptionIcon, OptionLabel } from "styles/SpaceDirectory/SpaceDirectory";
  
const SPACE_DIRECTORY  = observer((props) => {

const [isInfoShown, setInfoShown] = useState(false);
  
const handleClick = (event) => {
    event.preventDefault(); 
    setInfoShown(true);
    }


  const { spaceStore } = useDataStore();

  const spaces = spaceStore.spaces?.map(space => (
    <Space
      key={space.id} 
      space={space}
    />
  ))

  

  return (
    <SpaceDirectory>
      <Header>
        <Title>SPACES</Title>
        <Options>
          <Option onClick={async () => console.log("ADD SPACE") }>
            <OptionIcon>
              <Plus />
            </OptionIcon>
            <OptionLabel>
              SPACE
            </OptionLabel>
          </Option>
        </Options>
        <Options>
            <Option type='submit' onClick={handleClick} >
          {isInfoShown && <ShowNetworkInfo/>}
            <OptionIcon>
              <Plus />
            </OptionIcon>
            <OptionLabel>
              ADD NETWORK
            </OptionLabel>
          </Option>
        </Options>
      </Header>
      { spaces }
    </SpaceDirectory>
  );
});

export default SPACE_DIRECTORY

The onClick event fires and takes me to the following component:

Component:

import { observer } from 'mobx-react-lite'
import { useRouter } from 'next/router';
import { useEffect, useMemo, useState } from 'react';

import NetworkInformation from 'components/Forms/NetworkInformation';
import ShowNetworkInfo, { Header, FormNav, FormNavItem, FormBody } from 'styles/Forms/ShowNetworkInfo'
import { useDataStore } from 'stores/data';
import { Product } from 'models/Product';

type NetworkNode = any;
type Order = {
  selectedNetwork:Product
  items:Array<NetworkNode>
}

const SHOW_NETWORK_INFO = observer(() => {
  
  const router = useRouter();
  const page = parseInt(router.query.page?.toString())
  const { productStore } = useDataStore()
  const [order, setOrder] = useState<Order>({
    selectedNetwork:null,
    items:[]
  });

  useEffect(() => {
    const page = parseInt(router.query.page.toString());
    if ( order.selectedNetwork && page === 1 )
      router.push({ pathname:router.pathname, query: { ...router.query, page:2 }})

    if ( !order.selectedNetwork && page > 1 )
      router.push({ pathname:router.pathname, query: { ...router.query, page:1 }})

  },[ order.selectedNetwork ])

  const FormOptions = useMemo(() => {
    const options = [];
    switch(page){

      case 1:
        options.push(
          <NetworkInformation 
            key={`network-catalog`} 
            selectedNetwork={order.selectedNetwork}
            selectNetwork={( productId ) => {
              const targetProduct = productStore.products.find(product => product.pid === productId )
              productId === order.selectedNetwork?.pid ?
                router.push({ pathname:router.pathname, query: { ...router.query, page:2 }}) :
                setOrder({ ...order, selectedNetwork:targetProduct })
            }}
          />
        )
        break;
    }
    return options;
  }, [page]);

  return (
    <ShowNetworkInfo>
      <Header>Network Information</Header>
      {/* <FormNav>
        <FormNavItem 
          data-active={page === 1}
          onClick={() => {
            if( page !== 1 )
              router.push({ 
                pathname:router.pathname,
                query: { ...router.query, page:1 }
              })
          }}>
          1. SELECT
        </FormNavItem>
        <FormNavItem
          data-active={page === 2}
          onClick={() => {
            if( page !== 2 && !!order.selectedNetwork )
              router.push({ 
                pathname:router.pathname,
                query: { ...router.query, page:2 }
              })
          }}>
          2. CONFIGURE
        </FormNavItem>
        <FormNavItem
          data-active={page === 3}
          onClick={() => {
            if( page !== 3 )
              router.push({ 
                pathname:router.pathname,
                query: { ...router.query, page:3 }
              })
          }}>
          3. DEPLOY
        </FormNavItem>
      </FormNav> */}
      <FormBody>
        { FormOptions }
      </FormBody>
    </ShowNetworkInfo>
  )
});

export default SHOW_NETWORK_INFO

CodePudding user response:

router.query = {} in first render of the nextjs,

you have to add router.query.page to the dependencies array of the useEffect


useEffect(() => {
    if(!router.query.page) return;

    const page = parseInt(router.query.page.toString());
    if ( order.selectedNetwork && page === 1 )
      router.push({ pathname:router.pathname, query: { ...router.query, page:2 }})

    if ( !order.selectedNetwork && page > 1 )
      router.push({ pathname:router.pathname, query: { ...router.query, page:1 }})

  },[ order.selectedNetwork, router.query.page ])

  • Related