Joon K
Joon K

Reputation: 159

Why is data fetched from API using react-hook provided inconsistently?

I am trying to render some string of names using React-hook. The data is fetched from the '/api/getMoreCards' end point, which is defined in the controller file, and works fine.

The problem is that when I store the fetched data into 'data' of react-hook's useState object, it inconsistently gives access to the data. Let me be more specific:

import React, {useState, useEffect} from 'react';
import axios from 'axios';
const regeneratorRuntime = require("regenerator-runtime");

const HS = () => {
  const getData = async() => {
    const data = await axios.get('/api/getMoreCards')
    console.log(data)
    setData(data)
}
  const [data, setData] = useState({});
    useEffect(()=>{
      getData()
    },[]);

    return (
      <div>
        <h1>List of Cards</h1>
        **<div>{data.data[0].name}</div>**
      </div>
    );
}
export default HS;

This file is exported into App.js.

In the above code, the data.data[0].name is sometimes rendered on the localhost correctly, but most of the times, it gives me the error of:

"Uncaught TypeError: Cannot read property '0' of undefined at HS (hsContainer.js:76)" on the console.

In this case, the console logging on line 7 does not appear in the console at all.

I have tried closing and reopening VScode, changing the file to 'jsx', declared the data.data[0].name as a constant, changing the order of getData and useState codes, all of which were still inconsistent.

Here are my webpack.config.js and package.json file for reference:

Webpack.config.js

const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const config = {
  entry: [
    'react-hot-loader/patch',
    './src/index.js'
  ],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  mode: process.env.NODE_ENV,
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader'
        ]
      },
      {
        test: /\.svg$/,
        use: 'file-loader'
      },
      {
        test: /\.png$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              mimetype: 'image/png'
            }
          }
        ]
      }
    ]
  },
  resolve: {
    extensions: [
      '.js',
      '.jsx'
    ],
    alias: {
      'react-dom': '@hot-loader/react-dom'
    }
  },
  devServer: {
        contentBase: './dist',
        proxy: {
            '/api': 'http://localhost:3000',
            '/api/profile': 'http://localhost:3000',
        },
        historyApiFallback: true,
    },
  plugins: [
    new HtmlWebpackPlugin({
        template: `./public/index.html`,
    }),
  ],
};

module.exports = config;

package.json

{
  "name": "Solo-Project",
  "version": "1.0.0",
  "description": "",
  "main": "webpack.config.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node ./server/server.js",
    "build": "cross-env NODE_ENV=production webpack",
    "devother": "cross-env NODE_ENV=development webpack-dev-server --open --hot & nodemon ./server/server.js",
    "dev": "concurrently \"cross-env NODE_ENV=development webpack-dev-server --open --hot --inline --progress --colors --watch --content-base ./\" \"nodemon ./server/server.js\""
  },
  "repository": {
    "type": "git",
    "url": "git+https://I have replaced this for privacy on stackoverflow.git"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "https://I have replaced this for privacy on stackoverflow"
  },
  "homepage": "https://I have replaced this for privacy on stackoverflow",
  "devDependencies": {
    "@babel/core": "^7.11.6",
    "@babel/preset-env": "^7.11.5",
    "@babel/preset-react": "^7.10.4",
    "@hot-loader/react-dom": "^16.13.0",
    "babel-loader": "^8.1.0",
    "css-loader": "^4.3.0",
    "file-loader": "^6.1.0",
    "html-webpack-plugin": "^4.4.1",
    "style-loader": "^1.2.1",
    "url-loader": "^4.1.0",
    "webpack": "^4.44.1",
    "webpack-cli": "^3.3.12",
    "webpack-dev-server": "^3.11.0"
  },
  "dependencies": {
    "axios": "^0.20.0",
    "concurrently": "^5.3.0",
    "cross-env": "^7.0.2",
    "express": "^4.17.1",
    "nodemon": "^2.0.4",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-hot-loader": "^4.12.21"
  }
}

Upvotes: 0

Views: 38

Answers (2)

That Guy Kev
That Guy Kev

Reputation: 396

You can also check if "data" is valid first before rendering

<div>{data && data.data[0].name}</div>

Upvotes: 0

zero298
zero298

Reputation: 26877

There is nothing in data whenever you are accessing it. Either initialize it with an array that has an element or check if the array is empty before rendering.

const [data, setData] = useState({
    data: [{
        name: "tmp"
    }]
});

// or with optional chaining

return (
    <div> <h1>List of Cards</h1>
       {data?.data?.length && (
            <div>{data.data[0].name}</div>
       )}
    </div>
);

Upvotes: 1

Related Questions