React應用程式

範例應用程式是探索Adobe Experience Manager(AEM)無頭功能的絕佳方式。 此React應用程式示範如何使用持續查詢,使用AEM GraphQL API來查詢內容。 適用於JavaScript的AEM無頭式用戶端可用來執行支援應用程式的GraphQL持續查詢。

使用AEM Headless反應應用程式

檢視 GitHub原始碼

A 完整的逐步教學課程 說明此React應用程式的建置可用性。

必備條件

應在本機安裝下列工具:

  • [JDK 11](https://experience.adobe.com/#/downloads/content/software-distribution/en/general.html?1_group.propertyvalues.property=.%2Fjcr%3Acontent%2Fmetadata%2Fdc%3AsoftwareType&1_group.propertyvalues.operation=equals&1_group.propertyvalues.0_values=software-type%3Atoling&fulltext=Oracle%7E+JDK%7E+11%7E&orderby=%40jcr%3Cont%2Fjcr%3Alast&modified by.sort=dest&p.st=dest&p.llep.p.p=14)
  • Node.js v10+
  • npm 6+
  • Git

AEM需求

React應用程式可搭配下列AEM部署選項使用。 所有部署都需要 WKND Site v2.0.0+ 安裝。

React應用程式設計為連線至 AEM發佈 環境,但若React應用程式設定中提供驗證,則可從AEM Author取得內容。

如何使用

  1. 複製 adobe/aem-guides-wknd-graphql 存放庫:

    $ git clone git@github.com:adobe/aem-guides-wknd-graphql.git
    
  2. 編輯 aem-guides-wknd-graphql/react-app/.env.development 檔案和設定 REACT_APP_HOST_URI 指向您的target AEM。

    如果連線至製作例項,請更新驗證方法。

    # Server namespace
    REACT_APP_HOST_URI=http://localhost:4503
    
    #AUTH (Choose one method)
    # Authentication methods: 'service-token', 'dev-token', 'basic' or leave blank to use no authentication
    REACT_APP_AUTH_METHOD=basic
    
    # For Bearer auth, use DEV token (dev-token) from Cloud console
    REACT_APP_DEV_TOKEN=dev-token
    
    # For Service toke auth, provide path to service token file (download file from Cloud console)
    REACT_APP_SERVICE_TOKEN=auth/service-token.json
    
    # For Basic auth, use AEM ['user','pass'] pair (eg for Local AEM Author instance)
    REACT_APP_BASIC_AUTH_USER=admin
    REACT_APP_BASIC_AUTH_PASS=admin
    
  3. 開啟終端機並執行命令:

    $ cd aem-guides-wknd-graphql/react-app
    $ npm install
    $ npm start
    
  4. 新瀏覽器視窗應載入 http://localhost:3000

  5. 應用程式中應顯示來自WKND參考網站的歷險清單。

程式碼

以下是如何建置React應用程式、如何連線至AEM Headless以使用GraphQL持續查詢擷取內容的摘要,以及如何呈現該資料的摘要。 您可以在上找到完整的程式碼 GitHub.

持續查詢

遵循AEM無頭式最佳實務,React應用程式使用AEM GraphQL持續存在的查詢來查詢冒險資料。 應用程式使用兩個持續的查詢:

  • wknd/adventures-all 持續查詢,會傳回AEM中具有一組縮略屬性的所有歷險。 這個持續的查詢會驅動初始檢視的探險清單。
# Retrieves a list of all adventures
{
    adventureList {
        items {
            _path
            slug
            title
            price
            tripLength
            primaryImage {
                ... on ImageRef {
                _path
                mimeType
                width
                height
                }
            }
        }
    }
}
  • wknd/adventure-by-slug 持續查詢,其返回單個歷程,方法為 slug (可唯一識別冒險的自訂屬性),包含完整的屬性集。 這個持續的查詢可支援探險詳細資訊的檢視。
# Retrieves an adventure Content Fragment based on it's slug
# Example query variables:
# {"slug": "bali-surf-camp"}
# Technically returns an adventure list but since the the slug
# property is set to be unique in the CF Model, only a single CF is expected

query($slug: String!) {
  adventureList(filter: {
        slug: {
          _expressions: [ { value: $slug } ]
        }
      }) {
    items {
      _path
      title
      slug
      activity
      adventureType
      price
      tripLength
      groupSize
      difficulty
      price
      primaryImage {
        ... on ImageRef {
          _path
          mimeType
          width
          height
        }
      }
      description {
        json
        plaintext
      }
      itinerary {
        json
        plaintext
      }
    }
    _references {
      ...on AdventureModel {
        _path
        slug
        title
        price
        __typename
      }
    }
  }
}

執行GraphQL持續查詢

AEM持續查詢會透過HTTPGET執行,因此, AEM JavaScript適用的無頭式用戶端 用於 執行持續的GraphQL查詢 來抵御AEM,並將冒險內容載入應用程式中。

每個保存的查詢都有對應的React useEffect 鈎子 src/api/usePersistedQueries.js,會非同步呼叫AEM HTTPGET持續存在的查詢端點,並傳回冒險資料。

每個函式依次調用 aemHeadlessClient.runPersistedQuery(...),執行持續的GraphQL查詢。

// src/api/usePersistedQueries.js

/**
 * React custom hook that returns a list of adevntures by activity. If no activity is provided, all adventures are returned.
 *
 * Custom hook that calls the 'wknd-shared/adventures-all' or 'wknd-shared/adventures-by-activity' persisted query.
 *
 * @returns an array of Adventure JSON objects, and array of errors
 */
export function useAdventuresByActivity(adventureActivity) {
  ...
  // If an activity is provided (i.e "Camping", "Hiking"...) call wknd-shared/adventures-by-activity query
  if (adventureActivity) {
    // The key is 'activity' as defined in the persisted query
    const queryParameters = { activity: adventureActivity };

    // Call the AEM GraphQL persisted query named "wknd-shared/adventures-by-activity" with parameters
    response = await fetchPersistedQuery("wknd-shared/adventures-by-activity", queryParameters);
  } else {
    // Else call the AEM GraphQL persisted query named "wknd-shared/adventures-all" to get all adventures
    response = await fetchPersistedQuery("wknd-shared/adventures-all");
  }

  ...
}

...
/**
 * Private function that invokes the AEM Headless client.
 *
 * @param {String} persistedQueryName the fully qualified name of the persisted query
 * @param {*} queryParameters an optional JavaScript object containing query parameters
 * @returns the GraphQL data or an error message
 */
async function fetchPersistedQuery(persistedQueryName, queryParameters) {
  let data;
  let err;

  try {
    // AEM GraphQL queries are asynchronous, either await their return or use Promise-based .then(..) { ... } syntax
    const response = await aemHeadlessClient.runPersistedQuery(
      persistedQueryName,
      queryParameters
    );
    // The GraphQL data is stored on the response's data field
    data = response?.data;
  } catch (e) {
    // An error occurred, return the error messages
    err = e
      .toJSON()
      ?.map((error) => error.message)
      ?.join(", ");
    console.error(e.toJSON());
  }

  return { data, err };
}

檢視

React應用程式使用兩種檢視來呈現網頁體驗中的冒險資料。

  • src/components/Adventures.js

    調用 getAdventuresByActivity(..)src/api/usePersistedQueries.js 並在清單中顯示傳回的歷險。

  • src/components/AdventureDetail.js

    調用 getAdventureBySlug(..) 使用 slug 參數是透過 Adventures 元件,並顯示單一歷險的詳細資訊。

環境變數

數個 環境變數 用於連線至AEM環境。 預設連線至執行中的AEM發佈 http://localhost:4503. 更新 .env.development 檔案,若要變更AEM連線:

  • REACT_APP_HOST_URI=http://localhost:4502:設為AEM目標主機
  • REACT_APP_GRAPHQL_ENDPOINT=/content/graphql/global/endpoint.json:設定GraphQL端點路徑。 此React應用程式不會使用此值,因為此應用程式僅使用持續的查詢。
  • REACT_APP_AUTH_METHOD=:慣用的驗證方法。 選用,依預設不使用驗證。
    • service-token:使用服務憑證在AEM as a Cloud Service上取得存取權杖
    • dev-token:在AEMas a Cloud Service上使用開發代號進行本機開發
    • basic:透過本機AEM作者,將使用者/傳遞用於本機開發
    • 保留為空白,即可不進行驗證而連線至AEM
  • REACT_APP_AUTHORIZATION=admin:admin:設定在連線至AEM製作環境時要使用的基本驗證憑證(僅限開發用)。 如果連線至發佈環境,則不需要此設定。
  • REACT_APP_DEV_TOKEN:開發代號字串。 若要連線至遠端執行個體,除了基本驗證(user:pass)之外,您還可以透過雲端主控台,搭配DEV Token使用承載驗證
  • REACT_APP_SERVICE_TOKEN:服務憑據檔案的路徑。 若要連線至遠端執行個體,您也可以使用服務代號(從開發人員控制台下載檔案)來完成驗證。

代理AEM請求

使用Webpack開發伺服器時(npm start)專案需仰賴 代理設定 使用 http-proxy-middleware. 檔案的設定位置為 src/setupProxy.js 並需仰賴設定於的數個自訂環境變數 .env.env.development.

若連線至AEM製作環境,則對應的 驗證方法需要配置.

跨原始資源共用(CORS)

此React應用程式需仰賴在目標AEM環境上執行的AEM型CORS設定,並假設React應用程式執行於 http://localhost:3000 在開發模式中。 此 CORS設定WKND站點.

CORS設定

本頁內容