Fetch data into React component and render it

2019-08-18 22:51发布

问题:

Backend dev here trying to make a super scrappy app. Don't judge me. :P

Started from create-react-app. My App.js looks like this:

import React from 'react';
import ReactDOM from 'react-dom';
import './App.css';

class Table extends React.Component {
    constructor(props) {
        super(props);
    }

    componentDidMount() {
        fetch('/api/requiredUsers')
            .then(response =>
                {
                    this.setState({foo: response.json()});
                    console.log(this.state.foo);
                }
            );
    }

    render() {
        return (
            <div>
                <table className="table">
                    <thead>
                    <tr>
                        <th scope="col">#</th>
                        <th scope="col">Name</th>
                        <th scope="col">Age</th>
                        <th scope="col">Number</th>
                    </tr>
                    </thead>
                    <tbody>
                    {this.state.foo.map(person => (
                        <tr key={person.id}>
                            <th scope="row">{person.id}</th>
                            <td>{person.name}</td>
                            <td>{person.age}</td>
                            <td>{person.number}</td>
                        </tr>
                    ))}
                    </tbody>
                </table>
            </div>
        )
    }
}

export default Table;

ReactDOM.render(<Table />, document.getElementById('root'));

The response I get from localhost:8080/api/requiredUsers (where I am running a springboot app):

[{"id":8,"name":"christoph","age":32,"number":"555-555-5555"},
{"id":9,"name":"debra","age":31,"number":"555-555-5555"},
{"id":10,"name":"eric","age":29,"number":"555-555-5555"},
{"id":19,"name":"richard","age":20,"number":"555-555-5555"},
{"id":14,"name":"santiago","age":25,"number":"(555)555-5555"}]

When I comment out , I get a console.log print of:

Promise {<pending>}
__proto__: Promise
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: Array(5)
0: {id: 8, name: "christoph", age: 32, number: "555-555-5555"}
1: {id: 9, name: "debra", age: 31, number: "555-555-5555"}
2: {id: 10, name: "eric", age: 29, number: "555-555-5555"}
3: {id: 19, name: "richard", age: 20, number: "555-555-5555"}
4: {id: 14, name: "santiago", age: 25, number: "(555)555-5555"}
length: 5
__proto__: Array(0)

But when I don't comment it out, I get this error:

Uncaught TypeError: Cannot read property 'foo' of null
    at Table.render (App.js:34)
    at finishClassComponent (react-dom.development.js:8377)
    at updateClassComponent (react-dom.development.js:8345)
    at beginWork (react-dom.development.js:8966)
    at performUnitOfWork (react-dom.development.js:11798)
    at workLoop (react-dom.development.js:11827)
    at HTMLUnknownElement.callCallback (react-dom.development.js:104)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:142)
    at invokeGuardedCallback (react-dom.development.js:191)
    at replayUnitOfWork (react-dom.development.js:11302)
    at renderRoot (react-dom.development.js:11869)
    at performWorkOnRoot (react-dom.development.js:12422)
    at performWork (react-dom.development.js:12343)
    at performSyncWork (react-dom.development.js:12320)
    at requestWork (react-dom.development.js:12220)
    at scheduleWorkImpl (react-dom.development.js:12095)
    at scheduleWork (react-dom.development.js:12055)
    at scheduleRootUpdate (react-dom.development.js:12683)
    at updateContainerAtExpirationTime (react-dom.development.js:12711)
    at Object.updateContainer (react-dom.development.js:12730)
    at ReactRoot../node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render (react-dom.development.js:16030)
    at react-dom.development.js:16449
    at Object.unbatchedUpdates (react-dom.development.js:12530)
    at legacyRenderSubtreeIntoContainer (react-dom.development.js:16445)
    at Object.render (react-dom.development.js:16513)
    at Object../src/App.js (App.js:51)
    at __webpack_require__ (bootstrap e37a71bbed3a8bfb78c4:678)
    at fn (bootstrap e37a71bbed3a8bfb78c4:88)
    at Object../src/index.js (index.css?f255:26)
    at __webpack_require__ (bootstrap e37a71bbed3a8bfb78c4:678)
    at fn (bootstrap e37a71bbed3a8bfb78c4:88)
    at Object.0 (registerServiceWorker.js:117)
    at __webpack_require__ (bootstrap e37a71bbed3a8bfb78c4:678)
    at bootstrap e37a71bbed3a8bfb78c4:724
    at bootstrap e37a71bbed3a8bfb78c4:724
render @ App.js:34
finishClassComponent @ react-dom.development.js:8377
updateClassComponent @ react-dom.development.js:8345
beginWork @ react-dom.development.js:8966
performUnitOfWork @ react-dom.development.js:11798
workLoop @ react-dom.development.js:11827
callCallback @ react-dom.development.js:104
invokeGuardedCallbackDev @ react-dom.development.js:142
invokeGuardedCallback @ react-dom.development.js:191
replayUnitOfWork @ react-dom.development.js:11302
renderRoot @ react-dom.development.js:11869
performWorkOnRoot @ react-dom.development.js:12422
performWork @ react-dom.development.js:12343
performSyncWork @ react-dom.development.js:12320
requestWork @ react-dom.development.js:12220
scheduleWorkImpl @ react-dom.development.js:12095
scheduleWork @ react-dom.development.js:12055
scheduleRootUpdate @ react-dom.development.js:12683
updateContainerAtExpirationTime @ react-dom.development.js:12711
updateContainer @ react-dom.development.js:12730
./node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render @ react-dom.development.js:16030
(anonymous) @ react-dom.development.js:16449
unbatchedUpdates @ react-dom.development.js:12530
legacyRenderSubtreeIntoContainer @ react-dom.development.js:16445
render @ react-dom.development.js:16513
./src/App.js @ App.js:51
__webpack_require__ @ bootstrap e37a71bbed3a8bfb78c4:678
fn @ bootstrap e37a71bbed3a8bfb78c4:88
./src/index.js @ index.css?f255:26
__webpack_require__ @ bootstrap e37a71bbed3a8bfb78c4:678
fn @ bootstrap e37a71bbed3a8bfb78c4:88
0 @ registerServiceWorker.js:117
__webpack_require__ @ bootstrap e37a71bbed3a8bfb78c4:678
(anonymous) @ bootstrap e37a71bbed3a8bfb78c4:724
(anonymous) @ bootstrap e37a71bbed3a8bfb78c4:724
Show 5 more frames
index.js:2178 The above error occurred in the <Table> component:
    in Table (at App.js:51)

Consider adding an error boundary to your tree to customize error handling behavior.
__stack_frame_overlay_proxy_console__ @ index.js:2178
logCapturedError @ react-dom.development.js:9627
logError @ react-dom.development.js:9666
commitErrorLogging @ react-dom.development.js:9879
commitAllLifeCycles @ react-dom.development.js:11443
callCallback @ react-dom.development.js:104
invokeGuardedCallbackDev @ react-dom.development.js:142
invokeGuardedCallback @ react-dom.development.js:191
commitRoot @ react-dom.development.js:11578
completeRoot @ react-dom.development.js:12475
performWorkOnRoot @ react-dom.development.js:12425
performWork @ react-dom.development.js:12343
performSyncWork @ react-dom.development.js:12320
requestWork @ react-dom.development.js:12220
scheduleWorkImpl @ react-dom.development.js:12095
scheduleWork @ react-dom.development.js:12055
scheduleRootUpdate @ react-dom.development.js:12683
updateContainerAtExpirationTime @ react-dom.development.js:12711
updateContainer @ react-dom.development.js:12730
./node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render @ react-dom.development.js:16030
(anonymous) @ react-dom.development.js:16449
unbatchedUpdates @ react-dom.development.js:12530
legacyRenderSubtreeIntoContainer @ react-dom.development.js:16445
render @ react-dom.development.js:16513
./src/App.js @ App.js:51
__webpack_require__ @ bootstrap e37a71bbed3a8bfb78c4:678
fn @ bootstrap e37a71bbed3a8bfb78c4:88
./src/index.js @ index.css?f255:26
__webpack_require__ @ bootstrap e37a71bbed3a8bfb78c4:678
fn @ bootstrap e37a71bbed3a8bfb78c4:88
0 @ registerServiceWorker.js:117
__webpack_require__ @ bootstrap e37a71bbed3a8bfb78c4:678
(anonymous) @ bootstrap e37a71bbed3a8bfb78c4:724
(anonymous) @ bootstrap e37a71bbed3a8bfb78c4:724
Show 4 more frames
App.js:34 Uncaught TypeError: Cannot read property 'foo' of null
    at Table.render (App.js:34)
    at finishClassComponent (react-dom.development.js:8377)
    at updateClassComponent (react-dom.development.js:8345)
    at beginWork (react-dom.development.js:8966)
    at performUnitOfWork (react-dom.development.js:11798)
    at workLoop (react-dom.development.js:11827)
    at renderRoot (react-dom.development.js:11858)
    at performWorkOnRoot (react-dom.development.js:12422)
    at performWork (react-dom.development.js:12343)
    at performSyncWork (react-dom.development.js:12320)
    at requestWork (react-dom.development.js:12220)
    at scheduleWorkImpl (react-dom.development.js:12095)
    at scheduleWork (react-dom.development.js:12055)
    at scheduleRootUpdate (react-dom.development.js:12683)
    at updateContainerAtExpirationTime (react-dom.development.js:12711)
    at Object.updateContainer (react-dom.development.js:12730)
    at ReactRoot../node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render (react-dom.development.js:16030)
    at react-dom.development.js:16449
    at Object.unbatchedUpdates (react-dom.development.js:12530)
    at legacyRenderSubtreeIntoContainer (react-dom.development.js:16445)
    at Object.render (react-dom.development.js:16513)
    at Object../src/App.js (App.js:51)
    at __webpack_require__ (bootstrap e37a71bbed3a8bfb78c4:678)
    at fn (bootstrap e37a71bbed3a8bfb78c4:88)
    at Object../src/index.js (index.css?f255:26)
    at __webpack_require__ (bootstrap e37a71bbed3a8bfb78c4:678)
    at fn (bootstrap e37a71bbed3a8bfb78c4:88)
    at Object.0 (registerServiceWorker.js:117)
    at __webpack_require__ (bootstrap e37a71bbed3a8bfb78c4:678)
    at bootstrap e37a71bbed3a8bfb78c4:724
    at bootstrap e37a71bbed3a8bfb78c4:724

Please tell me how I can render this.

回答1:

You are missing another then (response.json() returns a promise)

fetch('/api/requiredUsers')
    .then(response => response.json())
    .then(data => this.setState({ foo: data }));

check if foo is something

             <tbody>
                {this.state.foo && this.state.foo.map(person => (
                    <tr key={person.id}>
                        <th scope="row">{person.id}</th>
                        <td>{person.name}</td>
                        <td>{person.age}</td>
                        <td>{person.number}</td>
                    </tr>
                ))}
                </tbody>


回答2:

response.json() returns a promise, not the data.

You need to extract the data first.

fetch('/api/requiredUsers')
    .then(response => response.json())
    .then(data => this.setState({ foo: data }));


回答3:

Define the state in the constructor as given below.

constructor(props) {
    super(props);
    this.state = {
       foo:[]
    }
}

This is occurring because in react life cycle, render() loads before componentdidmount() and foo is not defined before componentdidmount() runs. So there is no state named foo.