0

I am new to the front end technologies. My requirement is to make a post call to an external server. I started with creating the react app and used axios to make the call, but I was getting access denied due to CORS. Some posts on stackoverflow mentioned that I would need a proxy server to overcome this. Thus, I added an express part to the project as well. Below is my react and express codes.

React:

import React, { Component } from "react";

class App extends Component {
state = { posts: null };

componentDidMount() {
fetch("/posts")
  .then(res => {
    console.log(res);
    return res;
  })
  .then(posts => this.setState({ posts: posts }));
}

render() {
return (
  <div className="App">
    <h1>Users</h1>
    {this.state.posts}
  </div>
);
}
}

export default App;

Express:

var express = require("express");
var router = express.Router();
const axios = require("axios");

router.get("/", function(req, res, next) {
axios
.get("https://jsonplaceholder.typicode.com/posts")
.then(response => res.json(response.data))
.catch(err => next(err));
});

module.exports = router;

When I load the React app, I get the below error:

Error: Objects are not valid as a React child (found: [object Response]). If you meant to render a collection of children, use an array instead.
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
T Anna
  • 874
  • 5
  • 21
  • 52
  • what is the value for this `this.state.posts`. It needs to be valid React child. If not you need to convert them into valid children. Read more [objects-are-not-valid-as-a-react-child-if-you-meant-to-render-a-collection-of-c](https://stackoverflow.com/questions/52428879/objects-are-not-valid-as-a-react-child-if-you-meant-to-render-a-collection-of-c) and [objects-are-not-valid-as-a-react-child](https://stackoverflow.com/questions/41604539/objects-are-not-valid-as-a-react-child). You might be trying to show an object directly which is not possible – Sunil Chaudhary Jan 12 '20 at 18:01

4 Answers4

0

The returned response from the axios fetch is an object, with the payload in data. So you need to return that:

componentDidMount() {
  fetch("/posts")
    .then(res => {
      console.log(res);
      return res.data;  // <-- res.data instead of res;
    })
    .then(posts => this.setState({ posts: posts }));
}
Christian Fritz
  • 20,641
  • 3
  • 42
  • 71
  • I tried this. I don't get any error now, but the data is not being rendered on the page. Even on the console, I can see a response status 200 , but I can't see the response body. Also, i would like to mention one thing that if you go through my route code , you would see that I am actually returning response.data, so I'm not sure why do I need to mention res.data again in my react file. – T Anna Jan 12 '20 at 19:11
  • ah, I see. Yes, I guess I just don't know what your fetch function does. Because it "fetches" from `/posts/` but your server route is `/`. Could that be part of the issue? – Christian Fritz Jan 13 '20 at 00:10
0

I tested the code below and it worked fine. Run npm install --save axios before. It omits the express.js application, but maybe it will be helpful.

import React, {useState, useEffect} from 'react'
import ReactDOM from 'react-dom'
import Axios from 'axios'

const App = () => {

  const [posts, setPosts] = useState([])

  useEffect(() => {
    console.log('React works')
    Axios.get('http://jsonplaceholder.typicode.com/posts').then(res => {
      if (res.status === 200)
        setPosts(res.data)
      else
        console.log(res.status)
    }).catch(err => console.log(err))
  }, [])
 
  const mappedPosts = posts.map(post => <p key={post.id}>{post.title}</p>)

  return (
    <div className="App">
      {mappedPosts}
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'));
Adrian
  • 143
  • 5
  • That would mean that there is something wrong with ComponentDidMount function, because this.state.posts is empty. I also think that You should use `return res.data` instead of `return res` like @Christian Fritz mentioned, since it's a different request. You make one request in your express.js app and use its data property and another request in your react app and also use its data property. Request object alone also contains information about status code, time etc – Adrian Jan 12 '20 at 20:56
  • Tried that. Doesn't work. All i want is to render the data from this link : https://jsonplaceholder.typicode.com/posts . Can you please take a look at my code and let me know how to do that. – T Anna Jan 12 '20 at 21:13
  • Wait a sec, I'll edit this post and put there everything you need – Adrian Jan 12 '20 at 21:18
  • I need to use express as well. It works fine when I dont have express backend, but I need it to work with a backend. – T Anna Jan 12 '20 at 21:31
  • Sorry, I don't know express.js enough to help You. Maybe something with CORS? – Adrian Jan 12 '20 at 21:52
0

Actually in 2020 we dont need class components, componendDidMount etc more... you can do a clearly refactoring in your code like this:

import React, { useState, useEffect } from "react";

export default function App() {
    const [posts, setPosts] = useState([])

    useEffect(() => {
        async function getPosts(){
            const { data } = await fetch('/posts');
            setPosts(data);
        }

        getPosts();
    }, [])

    return (
        <div className="App">
           <h1>Users</h1>
           {posts.map(post => <p>{post}</p>}
        </div>
     );
}

Fábio BC Souza
  • 1,170
  • 19
  • 22
  • I tried this. I don't get an error now but I don't see the data being rendered on the page. – T Anna Jan 12 '20 at 19:15
  • console.log your data to see how it's comming, have in mind that the value is only what should be displayed. Exemple: If your post object is somenthing like: `{message: 'trump agains iran'}` so your out is something like: `

    {post.message}

    `
    – Fábio BC Souza Jan 12 '20 at 19:16
  • I added a console log before 'setPosts(data)'. Nothing is logged on the console. – T Anna Jan 12 '20 at 19:18
  • set at the view! Like `

    {console.log(post)}

    `
    – Fábio BC Souza Jan 12 '20 at 19:19
  • Still nothing. I can just see a warning on the console 'backend.js:6 ./src/App.js Line 7: 'getPosts' is defined but never used no-unused-vars'. Nothing apart from that. – T Anna Jan 12 '20 at 19:21
  • OWww I forgot to call, see I will edit the annswer! just call getPost() after creatign the function, inside the useEffect , as edited. – Fábio BC Souza Jan 12 '20 at 19:21
  • Now I get : TypeError: Cannot read property 'map' of undefined – T Anna Jan 12 '20 at 19:28
  • So let's take a look into the destruction data, inside useEffect remove `const {data} = ... ` and set without curly braces `cosnt data` and try console.log. We are almost there lol – Fábio BC Souza Jan 12 '20 at 19:31
  • Now I get : TypeError: posts.map is not a function. I ve updated as : const data = await fetch("/posts"); – T Anna Jan 12 '20 at 20:15
  • Yes, now totally console.log data before getting the error line, see what kind data you have, object or array of objects, show me what you get! – Fábio BC Souza Jan 12 '20 at 20:57
  • I have pasted it here : https://chat.stackoverflow.com/rooms/205840/discussion-between-t-anna-and-fabio-bc-souza – T Anna Jan 12 '20 at 21:08
0

Two things:

1) Grab your result from res.data because fetch returns an object (data, statusText, etc) when it resolves but you're mostly concerned about the data

2) Add an empty array to the state state : { posts : []} and then iterate over the array in the render method. Ensure you're not rendering an object. E.G {{post.name}} instead of just {{ post}}

Rowland
  • 1,728
  • 1
  • 12
  • 19