web-dev-qa-db-ja.com

TypeError:未定義のプロパティ「データ」を読み取ることができません-Reactjsの特定のレベルを超えてオブジェクト「プロパティ」にアクセスできません

axiosReactを使用してUseEffect経由でAPI呼び出しを行っています。
_dataを使用して、useStateという変数に応答を設定します

_const [data, setData] = useState({});
  setData(response);
_

応答はNASA APIからのものであり、この呼び出しに対して返されるオブジェクトは1つだけです(以下に貼り付けます)。

応答に「data」という名前を付け、それに「data」キーもあるので、URLをログに記録したい場合は、console.log(data.data.url)と入力すると、_app.js_でスムーズに機能します。主な機能。私の_card.js_コンポーネントでは、console.log(data)console.log(data.data)を正常にログに記録でき、期待どおりの結果が得られますが、console.log(data.data.url)または_(data.data.title)_何らかの理由でundefinedになるため、JSXのreturn関数で大きなエラーが発生し、サイトが読み込まれません。

_ TypeError: Cannot read property 'data' of undefined error.
_

それはオブジェクトのより高いレベルでうまく機能するので、私は自分の名前付けに何か問題があるとは思いません。 console.log(data.data)が機能し、目の前に次のレベルのプロパティが表示されます。

私は文字通りconsole.logingしています:

_{console.log('FROM INSIDE THE RETURN')}
{console.log(props.data)}  // works, displays object {}
{console.log(props.data.data)}  //works, displays object one level lower   
{console.log(props.data.data.url)}  // type error. You name the property.
_

言うまでもなく、これは機能しません。これが割り当てへの私の最初のアプローチでした。

_<img src={props.data.data.url}/>
_

それは、次のように上流のオブジェクトのトップレイヤーを削って、チームリーダーの助けを借りてプログラムを機能させることを意味します。

_SetData(response.data)

// as opposed to 
SetData(response)

// and then using 
<img src={props.data.url}/>
_

したがって、小道具の最下部に到達する必要はありませんでしたが、明確にするために、特にn-1層まで正常に機能した場合に、コンパイラーがコンパイラーに与える理由と違いを知りたいと思います(nは数値)オブジェクトのレイヤーの。

'data'が重複せず、動作が同じになるように、データ変数の1つの名前を変更しました。

あなたの助けと洞察をありがとう!あなたが共有できる洞察と私の質問に対するフィードバックに本当に感謝しています。

これが私が作業しているオブジェクトです。

_     {
        data: {
            copyright: "Bryan Goff",
            date: "2020-03-18",
            explanation: "What's happening behind...[truncated]...Florida, USA.",
            hdurl: "https://apod.nasa.gov/apod/image/2003/AntiCrepRays_Goff_3072.jpg",
            media_type: "image",
            service_version: "v1",
            title: "Anticrepuscular Rays over Florida",
            url: "https://apod.nasa.gov/apod/image/2003/AntiCrepRays_Goff_960.jpg"
        },
        status: 200,
        statusText: "OK",
        headers: {
            contenttype: "application/json"
        },
        config: {
            url: "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY",
            method: "get",
            headers: {
                Accept: "application/json, text/plain, */*"
            },
            transformRequest: [
                null
            ],
            transformResponse: [
                null
            ],
            timeout: 0,
            xsrfCookieName: "XSRF-TOKEN",
            xsrfHeaderName: "X-XSRF-TOKEN",
            maxContentLength: -1
        },
        request: {}
    }
_
6
gcr

これは確かに興味深い課題です。
ステップバイステップの分析をして、私たちが同意するかどうか見てみましょう:

// this initializes `data = {}` when the app first launches
const [data, setData] = useState({});

// Chances are, you are using this within the "useEffect"
// If so at that point, the above `data = response`
setData(response)

ほとんどの場合、axios内でuseEffect NASA API呼び出しを行っています。
それでは、API呼び出しに絞り込みましょう。

多くの場合、API呼び出しは非同期です(非ブロッキング)。
つまり、このデータフェッチプロセスは、クライアント側が他の「アクティビティ」を実行することを妨げません。それが邪魔にならないように、共有コードに戻ってみましょう:

説明1:データのフェッチ中に発生する可能性があります

// works, because initially "data = {}"
{console.log(props.data)}

// works, displays object one level lower
{console.log(props.data.data)}
// Explaining this...
// APIs are often backend apps that query a database for actual data. 
// This returned data is stored in "literals" (often arrays/lists/objects).

// type error. You name the property.
{console.log(props.data.data.url)}
// Based on the above explanation, 
// despite the second `data` being an Object literal, 
// "url" isn't yet defined since the API is still "querying" the database

説明2:名前空間の競合の可能性があります

// If all is fine based on "explanation 1", 
// then this could be a "namespace" conflict during compilation.

// At compilation, JS finds two variables named "data"
// 1. The initial data value, 
   data = {}
// 2. The returned data key,
   {
     data: {...},
   }
// If we had a returned response as follows:
   results = {
     data: {...},
   }
// we probably would have something like this working 
{console.log(response.data.result.data.url)}

// And this might explains why these work...
{console.log(response.data.url)}
<img src={props.data.url}/>

ここでは、頑固なJavaScriptを扱っています。
そして、そのため、現在増加している多くの大きなReactjsプロジェクトがTypeScriptに関与しているのはおそらくそのためです。

2
MwamiTovi

私の推測では、api呼び出しに時間がかかり、api呼び出しが戻る前に値を設定しようとしています。追加のisLoading状態を使用して、APIがまだ実行されているかどうかを確認してください

import React from 'react';

const Component = () => {  
const [isLoading,setIsLoading] = useState(true)
const [data, setData] = useState({});

useEffect(()=>{
  setTimeout(()=>fetch('https://jsonplaceholder.typicode.com/users/1')
    .then(response => response.json())
    .then(json => {        
        setData(json)
      setIsLoading(false)        
    }),1000)

},[0])


return(
  isLoading ? 'Loading...' :
    <div>
      <h1>Hello {data.name}!</h1>
      <p>Your username is {data.username}</p>
    </div>
  )
}

export default Component
2
muddassir