开发者问题收集

未捕获(在承诺中)TypeError:当尝试在 ReactJs 中捕获 API 数据时,无法读取未定义的属性

2019-06-15
5974

我正在使用 ReactJS 开发货币转换器应用程序。该程序用于将一种货币转换为另一种货币。该应用程序有一个表单,其中包含一个带有提交按钮的字段。此外,它还默认初始货币为“10 美元”。

当用户在字段中输入货币缩写(例如:KRW)并单击提交按钮时。表单下方将显示从 USD 到 KRW 的转换结果。如果用户想要添加更多货币,则“KRW”转换结果下方将显示另一种选择货币。

当我尝试使函数在用户在字段中提交货币缩写时显示结果时。

这是错误:

Uncaught (in promise) TypeError: Cannot read property 'rates' of undefined
    at Currency.render (App.js:402)
    at finishClassComponent (react-dom.development.js:15319)
    at updateClassComponent (react-dom.development.js:15274)
    at beginWork (react-dom.development.js:16262)
    at performUnitOfWork (react-dom.development.js:20279)
    at workLoop (react-dom.development.js:20320)
    at renderRoot (react-dom.development.js:20400)
    at performWorkOnRoot (react-dom.development.js:21357)
    at performWork (react-dom.development.js:21267)
    at performSyncWork (react-dom.development.js:21241)
    at requestWork (react-dom.development.js:21096)
    at scheduleWork (react-dom.development.js:20909)
    at Object.enqueueSetState (react-dom.development.js:11595)
    at App.push../node_modules/react/cjs/react.development.js.Component.setState (react.development.js:336)
    at Object.App.addCurrency [as onSubmit] (App.js:34)
    at Form.handleSubmit (App.js:204)

这是我的代码:

class Currency extends React.Component {
render() {
        const p = this.props;
        return (
            <div className="currency">
                {/*<span className="currencyText">&#x3C;Currency/&#x3E;</span>*/}
                <div className="currencyInfo">
                    <div>{"1 "+p.base + " = " }</div>
                    <div>{p.data.rates}</div> {/*this is (App.js:402)*/}

                </div>
            </div>
        );
    }
}

相反,如果我像这样编写 Apps.js:402 代码:

<div>{p.data}</div>

并运行该应用程序,并检查 chrome 中的控制台,该行的结果为空。

我指的是图片上的数据:

控制台结果

这是控制台 prop p 的结果:

result of prop p in console.log

有没有什么解决方案,以便我可以从货币中检索数据汇率?

2个回答

理想情况下,您希望通过某种方式来管理组件中的 loadingno-data 状态,具体取决于您的 api 在没有数据时返回的内容 - 您可能必须以不同的方式进行管理,但这也是您应该涵盖的场景。您的数据似乎来自名为 rates 的 prop,而不是 data ,后者是一个具有多个键的对象。

我不确定您的代码结构,但这种迭代和检查加载/无数据状态也可能在父组件中完成。

    class Currency extends React.Component {
    render() {
            const p = this.props;
            const { rates = {} } = p;
            const hasData = Object.keys(rates).length > 0;
            return !p.loading ? (
                <div className="currency">
                    <div className="currencyInfo">
                        { hasData ?
                        <>
                          <div>{"1 "+p.base + " = " }</div>
                          {Object.entries(rates).map(([k, v]) => <div key={k}>{`${k}: ${v}`}</div>)}
                        </> : <p>No data available</p>
                        }
                    </div>
                </div>
            ) : <Loader />
        }
    }

在父组件中,您可以执行以下操作:

    class ParentComp extends React.Component {
      public state = { loading: true, rates: {} };

      componentDidMount() {
        await this.fetchData(...); // could set loading to false on success
      }

      render() {
        const { rates = {} } = this.state;
        const hasData = Object.keys(rates).length > 0;
        return (
          !this.state.loading ?
            hasData ?
              Object.entries(rates).map(([k, v]) => <Currency key={k} name={k} value={v} ... />)
              : <p>No data available</p>
            : <Loader />
        );
      }
    }

然后在您的子组件中:

class Currency extends React.Component {
  render() {
    return  (
      <div className='currency'>
        <div className='currencyInfo'>
            <div>{`${this.props.name}: ${this.props.value}`}</div>
        </div>
      </div>
    );
  }
}

致谢:

感谢 @Codebling 指出在键的

中不必要地添加 v (值)
deowk
2020-03-13

我假设您的货币组件是一个子组件,并且它有一个父组件。

在将“数据”传递给子组件之前,只需为其初始化一个值即可。

const Child = props => {
  return(
    <div>
      Child
      {props.data.country}
    </div>
  )
}

const Parent = props => {

  // initiate state value to your variables that you are using.
  let [data, set_data] = useState(
    // this is where your error reside, you did not initiate a value.
    { country: 'abc'}
  );

  // api call
  useEffect(()=>{
    axios.get('http://ip-api.com/json/24.48.0.1',{})
    .then(function (response) {
        console.log(response.data);
      set_data(response.data)
    })
    .catch(function (error) {
      console.log(error.config);
    });
  }, [])

  return(
    <div>
      Parent
      <Child data={data}></Child>
    </div>
  )
}
export default Parent;
Mike Musni
2020-03-13