Search code examples
javascriptreactjsreact-hooksreact-routeruse-effect

React component fetches JSON correctly for one route, but returns "You need to enable JavaScript to run this app" for another


I have a component called Comments which uses useEffect() to fetch a local json file with dummy data. React-router is set up so the /comments endpoint renders this component directly.

Another route, /video/:watchId, instead renders to a component which contains the Comments component. The /comments endpoint works perfectly, but the same api call in the video endpoint fails to return the Json, and I get the error: "SyntaxError: Unexpected token < in JSON at position 0" because the response is type HTML instead of JSON.

I'm newish to react so perhaps I'm missing something obvious. What's going on?

App.js:

import React, { Component, useState } from 'react';
import {
  BrowserRouter as Router,
  Switch,
  Route
} from 'react-router-dom';
import '../styles/App.css';
import Home from './Home'
import Comments from './Comments'
import VideoPage from './VideoPage'

function App(){
  return (
    <Router>
      <Switch>
        <Route exact path="/"><Home/></Route>
        <Route path="/comments">
          <Comments video="watchId" top={true}/>
        </Route>
        <Route path="/video/:watchId">
          <VideoPage/>
        </Route>
      </Switch>
    </Router>
  );
}

export default App;

commentsApi.js:

export const getTopComments = (videoId) => {
    return fetch('data/topComments.json')
    .then( response => response.json());
}

export const getReplies = (parent) => {
    return fetch('data/commentReplies.json')
    .then( response => response.json());}

Comments.js:

import React, { useEffect, useState, useContext } from 'react';
import { getTopComments, getReplies } from '../apis/commentApi';
import CommentCard from './CommentCard'

const Comments = (props) => {

    const [comments, setComments] = useState([]);

    useEffect(() => {
        if(props.top){
            getTopComments(props.video)
            .then(cmts => {console.log(cmts); setComments(cmts); })
            .catch(error => console.log(error));
        }

        else{
            getReplies(props.video)
            .then(cmts => { setComments(cmts); })
            .catch(error => console.log(error));
        }
    }, [setComments]);
    
    return (
        comments
        ?
        comments.map(comment => <CommentCard key={ comment.id } comment={ comment } />)
        :
            <div>hell</div>
    );
}

export default Comments

VideoPage.js:

import React from "react";
import Comments from "./Comments"
import {useParams} from "react-router-dom";

const VideoPage = (props) => {
    const {watchId} = useParams()
    console.log(watchId)
    return (
        <div>
        hello world
        <Comments top={true} video={watchId}/>
        </div>
      );
}

export default VideoPage

Note: replacing with , the exact call from App.js, does not help.

When inspecting the /comments route: enter image description here

When inspecting the /video/{anything} route: enter image description here


Solution

  • I fixed this problem by changing the commentApi.js file as follows:

    export const getTopComments = (videoId) => {
        console.log("top hit")
        return fetch(`${process.env.PUBLIC_URL}/data/topComments.json`,{
            headers : { 
              'Content-Type': 'application/json',
              'Accept': 'application/json'
             }
          })
        .then( response => response.json());
    }
    
    export const getReplies = (parent) => {
        return fetch(`${process.env.PUBLIC_URL}/data/commentReplies.json`,{
            headers : { 
              'Content-Type': 'application/json',
              'Accept': 'application/json'
             }
          })
        .then( response => response.json());
    }
    

    I still don't know why it worked inconsistently before.