【问题标题】:Setting response from axios to state设置从 axios 到 state 的响应
【发布时间】:2018-09-27 10:23:20
【问题描述】:

当我在获取 axios 请求后尝试 setState 时,似乎我没有准备好呈现数据。在控制台中,我收到了响应,但无法访问该状态下的响应。

import React, { Component } from 'react';
import axios from 'axios';
import { Grid, Row, Col } from 'react-flexbox-grid';
import Avatar from '@material-ui/core/Avatar';
import Button from '@material-ui/core/Button';
import stylefile from './stylefile';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import { withStyles } from '@material-ui/core/styles';
import '../App.css';

class TitleBar extends Component {
    constructor() {
        super();
        this.state ={
            data:[],
        }
      }

    componentDidMount() {
        axios.get('http://api.abc',
            {
                headers: { "Postman-Token": "abc"}
            })
            .then((response) => {
                console.log(response.data);
                this.setState({
                    data: response.data,
                })
            })
            .catch((error) => {
                console.log(error)
            })
    }

  render() {
    const { classes } = this.props;
    console.log(this.state.data,"data response")
    return (
        <div>
            {
                this.state.data.map(((item,key) => (
                 <div>
                     //
                 </div>
             )))}
        </div>
    );
  }
}

export default withStyles(stylefile)(TitleBar);
          console.log(error);
        });
    }

//console.log(this.state.data) -- 未定义

【问题讨论】:

  • 你在哪里以及如何检查这样的状态?
  • 注意在 ComponentWillMount() 中使用 setState。当你在那里使用 setState 时,React 不会触发重新渲染,那么应用程序就不会看到状态中的 response.data。
  • 正如我在提供的答案的 cmets 中所说,我同意这里的建议,但如果 setState 在异步作业之后完成,componentWillMount 会触发渲染。这就是为什么我想知道 OP 在哪里使用console.log
  • 那么,你能在你的获取请求中看到你的数据吗? console.log(response.data); 另外,你在你的render 方法中记录了它,你说它是undefined here,对吧?
  • 完全是@devserkan先生

标签: javascript reactjs axios


【解决方案1】:

您的 API 响应对象包含如下对象:

const response = {
  data: {
    MESSAGE: "List details Fetch successful",
    STATUS: "SUCCESS",
    DATA: [
      { id: 1, name: "foo" },
      { id: 2, name: "bar" },
      { id: 3, name: "baz" }
    ],
    HASH: "3--0"
  }
};

所以,您需要 response.data.DATA 来代表您的状态:

this.setState( { data: response.data.DATA } );

这是一个模仿你的情况的工作示例。

const remoteData = {
  data: {
    MESSAGE: "List details Fetch successful",
    STATUS: "SUCCESS",
    DATA: [
      { id: 1, name: "foo" },
      { id: 2, name: "bar" },
      { id: 3, name: "baz" },
    ],
    HASH: "3--0",
  },
};

const fakeRequest = () =>
  new Promise( resolve => setTimeout( () => resolve( remoteData ), 1000 ) );

class App extends React.Component {
  state = {
    data: [],
  };

  componentDidMount() {
    fakeRequest().then( response => this.setState( { data: response.data.DATA } ) );
  }

  render() {
    return (
      <div>
        {this.state.data.map( el => (
          <div key={el.id}>
            <p>{el.id}</p>
            <p>{el.name}</p>
          </div>
        ) )}
      </div>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById( "root" )
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

【讨论】:

    【解决方案2】:

    来自React official docs

    componentWillMount() 在挂载之前被调用。它在 render() 之前调用,因此在该方法中同步调用 setState() 不会触发额外的渲染

    另外,应该使用 componentDidMount,因为 componentWillMount 在新版本的 react 中已被弃用。

    componentDidMount() {
            axios.get('http://api./abc',
                {
                    headers: { "Postman-Token": "abc" }
                })
                .then((response) => { //use arrow to get setState on this call without any extra binding or placeholder variable
                    console.log(response.data);
                    this.setState({
                        data: response.data,
                    })
                })
                .catch((error) => {
                    console.log(error)
                })
        }
    

    【讨论】:

    • 我同意componentDidMount 的建议,但 OP 正在使用异步作业更新状态,因此在此之后,它会触发重新渲染。
    • 我在映射时遇到错误 .. 就像 his.state.data.map 不是函数 this.state.data.map(((item,key) => (
    • @SupriyaBhart,请用您的整个组件代码更新您的问题。
    • @SupriyaBhart 它看起来像 response.data 不是一个数组。请检查响应结构
    • @RIYAJKHAN,我也怀疑,但无论如何,在日志中一定不能是undefined,我的意思是在render 方法中。
    【解决方案3】:

    尝试修复这些代码行:

      constructor(props) { //fixed
        super(props); //fixed
        this.state ={
            data:[],
        }
      }
    

    这正是 ReactJS 为 class component 设置 constructor() 方法的方式。我们只是在使用它时遵守 React 的规则。

    来自Official React Document,他们说:

    React 组件的构造函数在挂载之前被调用。在为 React.Component 子类实现构造函数时,您应该在任何其他语句之前调用 super(props)。否则,this.props 将在构造函数中未定义,这可能会导致错误。

    有关contructor() 方法的更多信息:https://reactjs.org/docs/react-component.html#constructor

    这是一个工作示例,我已经为你做了一个参考。

    演示现已在 CodeSandBox 上提供:https://codesandbox.io/s/8xvn8yl1l2

    TitleBar.js

    import React, { Component } from 'react';
    import axios from 'axios';
    export default class TitleBar extends Component {
      constructor(props) {
        super(props);
        this.state = {
          data: []
        };
      }
      componentDidMount() {
        axios
          .get('https://jsonplaceholder.typicode.com/posts')
          .then(res => {
            console.log(res.data);
            this.setState({ data: res.data });
          })
          .catch(err => console.log(err.message));
      }
      render() {
        return (
          <div>
            {this.state.data.map(i => (
              <div key={i.id}>
                <h2>{i.title}</h2>
              </div>
            ))}
          </div>
        );
      }
    }

    App.js

    import React, { Component } from 'react';
    import TitleBar from './components/TitleBar';
    
    class App extends Component {
      render() {
        return (
          <div>
            <TitleBar></TitleBar>
          </div>
        );
      }
    }
    
    export default App;

    按照这个例子,如果this.state.data仍然是undefine,那么为了成功调试,我们可以关注两件事:

    1.响应数据对象的结构。在您的情况下,解决方案可能是

    this.setState({
       data: response.data.DATA  
    })
    

    2.API 是否按预期工作。

    希望对您有所帮助。

    【讨论】:

    • 是的,我认为响应结构@Thankyou sir
    猜你喜欢
    • 2021-06-23
    • 1970-01-01
    • 2021-08-01
    • 1970-01-01
    • 2018-02-16
    • 2019-01-19
    • 1970-01-01
    • 2017-05-02
    • 2017-06-21
    相关资源
    最近更新 更多