How to access URL param to update component state in class component?

Viewed 135

I have a React component that is calling two API URLs, and the fetches are working now. But I want to use the URL handle which is structure like localhost://site/coins/[handle] as a parameter to the fetch different data points.

The way I planned it is to use:

import { useRouter } from 'next/router'
const router = useRouter()

But I am getting an error:

Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

Here is my component:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      coin: 'bitcoin',
      CoinData: [],
      historicData: [],
      DataisLoaded: false,
    };
  }

  componentDidMount() {
    fetch(
      'https://api.coingecko.com/api/v3/simple/price?ids=' +
        this.state.coin +
        '&vs_currencies=usd&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true&include_last_updated_at=true'
    )
      .then((res) => res.json())
      .then((json) => {
        this.setState({
          CoinData: json,
          DataisLoaded: true,
        });
      });
    fetch(
      'https://api.coingecko.com/api/v3/coins/' +
        this.state.coin +
        '/market_chart?vs_currency=usd&days=3'
    )
      .then((res) => res.json())
      .then((json) => {
        this.setState({
          historicData: json,
        });
      });
  }

  render() {
    const { DataisLoaded, CoinData, historicData, coin } = this.state;

    // console.log(processedData);
    if (!DataisLoaded) return <Skeleton />;

    return (
      <Dashboard>
        <DashboardHeader />
        <DashboardSidebar />
        <Main>
          <TopContainer>
            <div className='topContent'>
              <div role='presentation'>
                <Breadcrumbs aria-label='breadcrumb'>
                  <Link
                    underline='hover'
                    href='/'
                    fontSize='small'
                    fontFamily='Titillium Web'
                    color='#898181'
                  >
                    DefiPlatform
                  </Link>
                  <Link
                    underline='hover'
                    color='#898181'
                    href='/coins/'
                    fontSize='small'
                  >
                    Coins
                  </Link>
                  {/* <Typography color="#fff" fontSize="12px">{router.query.handle}</Typography> */}
                </Breadcrumbs>
              </div>
              <div className='coinMain'>
                <h1>
                  bitcoin
                  <Chip
                    label='BTC'
                    variant='outlined'
                    style={{ color: 'white', borderColor: '#251B55' }}
                  />
                </h1>
                <div>
                  <Chip
                    icon={<LinkIcon style={{ color: '#CECECE' }} />}
                    size='small'
                    label='Bitcoin.org'
                    style={{
                      color: '#CECECE',
                      marginTop: '5px',
                      marginRight: '5px',
                      backgroundColor: '#241E4E',
                    }}
                  />
                  <Chip
                    icon={<ArticleOutlinedIcon style={{ color: '#CECECE' }} />}
                    size='small'
                    label='Whitepaper'
                    style={{
                      color: '#CECECE',
                      marginTop: '5px',
                      marginRight: '5px',
                      backgroundColor: '#241E4E',
                    }}
                  />
                </div>
              </div>
            </div>
            <div className='coinPrice'>
              <div>
                <span className='coin_label'>bitcoin Price (BTC)</span>
                <h2>
                  {CoinData[this.state.coin].usd.toLocaleString('en-US', {
                    maximumFractionDigits: 2,
                  })}{' '}
                  <Ticker Value='1.68%' Variant='BG' />
                </h2>
              </div>
              <div className='coinComparison'>
                <div className='compareData'>12.47 ETH</div>
                <Ticker Value='2%' Variant='outline' />
              </div>
            </div>
          </TopContainer>

          <MainCards>
            <Card>
              <h6>Bitcoin to USD Chart</h6>
              {this.state.coin}
              {JSON.stringify(CoinData[this.state.coin])}
              {JSON.stringify(historicData.prices)}
              {}
            </Card>
            <Card>
              <h6>BTC Price Statistics</h6>
            </Card>
          </MainCards>
        </Main>
      </Dashboard>
    );
  }
}

export default App;
1 Answers

As the error mentions, React Hooks can only be called inside a function component. You're using a class component, so you can't call useRouter.

To access the router instance inside a class component you have to use the withRouter HOC. You can then access the router from this.props.router.

import { withRouter } from 'next/router'

class App extends React.Component {
    // Your `constructor` code here

    componentDidMount() {
        console.log(this.props.router); // Logs the `router` object
        // Remaining code here
    }

    // Your `render` code here
}

export default withRouter(App);
Related