片段
在 Relay 中,宣告 React 元件資料依賴關係的主要建構區塊是GraphQL 片段。片段是 GraphQL 中可重複使用的單元,代表要從Schema中公開的 GraphQL 類型查詢的一組資料。
實際上,它們是 GraphQL 類型上欄位的選擇
fragment UserFragment on User {
name
age
profile_picture(scale: 2) {
uri
}
}
為了在您的 JavaScript 程式碼中宣告片段,您必須使用 graphql
標籤
const {graphql} = require('react-relay');
const userFragment = graphql`
fragment UserFragment_user on User {
name
age
profile_picture(scale: 2) {
uri
}
}
`;
渲染片段
為了渲染片段的資料,您可以使用 useFragment
Hook
import type {UserComponent_user$key} from 'UserComponent_user.graphql';
const React = require('React');
const {graphql, useFragment} = require('react-relay');
type Props = {
user: UserComponent_user$key,
};
function UserComponent(props: Props) {
const data = useFragment(
graphql`
fragment UserComponent_user on User {
name
profile_picture(scale: 2) {
uri
}
}
`,
props.user,
);
return (
<>
<h1>{data.name}</h1>
<div>
<img src={data.profile_picture?.uri} />
</div>
</>
);
}
module.exports = UserComponent;
讓我們提煉一下這裡發生的事情
useFragment
接受一個片段定義和一個片段參考,並傳回該片段和參考的相應data
。- 這類似於
usePreloadedQuery
,它接受查詢定義和查詢參考。
- 這類似於
- 片段參考是 Relay 用來讀取片段定義中宣告的資料的物件;如您所見,
UserComponent_user
片段本身僅宣告User
類型上的欄位,但我們需要知道要從哪個特定使用者讀取這些欄位;這就是片段參考對應的內容。換句話說,片段參考就像一個指向我們要從中讀取資料的特定類型實例的指標。 - 請注意,元件會自動訂閱片段資料的更新:如果此特定
User
的資料在應用程式中的任何位置更新(例如,透過提取新資料或修改現有資料),則元件將自動以最新的更新資料重新渲染。 - 當編譯器執行時,Relay 將自動為任何宣告的片段產生 Flow 類型,因此您可以使用這些類型來宣告元件
props
的類型。- 產生的 Flow 類型包括片段參考的類型,它是帶有
$key
後綴的類型:<fragment_name>$key
,以及資料形狀的類型,它是帶有$data
後綴的類型:<fragment_name>$data
;這些類型可以從使用以下名稱產生的檔案中導入:<fragment_name>.graphql.js
。 - 我們使用我們的lint 規則來強制執行在使用
useFragment
時正確宣告片段參考 prop 的類型。透過使用正確類型的片段參考作為輸入,傳回的data
類型將自動進行 Flow 類型化,而無需顯式註釋。 - 在我們的範例中,我們將
user
prop 類型化為useFragment
所需的片段參考,這對應於從UserComponent_user.graphql
導入的UserComponent_user$key
,這表示上述data
的類型將為:{ name: ?string, profile_picture: ?{ uri: ?string } }
。
- 產生的 Flow 類型包括片段參考的類型,它是帶有
- 片段名稱需要是全域唯一的。為了輕鬆實現這一點,我們使用以下基於模組名稱後接識別碼的慣例來命名片段:
<module_name>_<property_name>
。這使得輕鬆識別哪些片段在哪些模組中定義,並避免在同一個模組中定義多個片段時發生名稱衝突。
如果需要在同一個元件內渲染來自多個片段的資料,則可以多次使用 useFragment
import type {UserComponent_user$key} from 'UserComponent_user.graphql';
import type {UserComponent_viewer$key} from 'UserComponent_viewer.graphql';
const React = require('React');
const {graphql, useFragment} = require('react-relay');
type Props = {
user: UserComponent_user$key,
viewer: UserComponent_viewer$key,
};
function UserComponent(props: Props) {
const userData = useFragment(
graphql`
fragment UserComponent_user on User {
name
profile_picture(scale: 2) {
uri
}
}
`,
props.user,
);
const viewerData = useFragment(
graphql`
fragment UserComponent_viewer on Viewer {
actor {
name
}
}
`,
props.viewer,
);
return (
<>
<h1>{userData.name}</h1>
<div>
<img src={userData.profile_picture?.uri} />
Acting as: {viewerData.actor?.name ?? 'Unknown'}
</div>
</>
);
}
module.exports = UserComponent;
組合片段
在 GraphQL 中,片段是可重複使用的單元,這表示它們可以包含其他片段,因此一個片段可以包含在其他片段或查詢中
fragment UserFragment on User {
name
age
profile_picture(scale: 2) {
uri
}
...AnotherUserFragment
}
fragment AnotherUserFragment on User {
username
...FooUserFragment
}
使用 Relay,您可以透過使用元件組合和片段組合以類似的方式組合片段元件。每個 React 元件都負責提取其直接子系的資料依賴關係,就像它必須了解其子系的 prop 才能正確渲染它們一樣。此模式表示開發人員能夠在本地推理元件,它們需要哪些資料、它們渲染哪些元件,但 Relay 能夠推導整個 UI 樹的資料依賴關係的全域檢視。
/**
* UsernameSection.react.js
*
* Child Fragment Component
*/
import type {UsernameSection_user$key} from 'UsernameSection_user.graphql';
const React = require('React');
const {graphql, useFragment} = require('react-relay');
type Props = {
user: UsernameSection_user$key,
};
function UsernameSection(props: Props) {
const data = useFragment(
graphql`
fragment UsernameSection_user on User {
username
}
`,
props.user,
);
return <div>{data.username ?? 'Unknown'}</div>;
}
module.exports = UsernameSection;
/**
* UserComponent.react.js
*
* Parent Fragment Component
*/
import type {UserComponent_user$key} from 'UserComponent_user.graphql';
const React = require('React');
const {graphql, useFragment} = require('react-relay');
const UsernameSection = require('./UsernameSection.react');
type Props = {
user: UserComponent_user$key,
};
function UserComponent(props: Props) {
const user = useFragment(
graphql`
fragment UserComponent_user on User {
name
age
profile_picture(scale: 2) {
uri
}
# Include child fragment:
...UsernameSection_user
}
`,
props.user,
);
return (
<>
<h1>{user.name}</h1>
<div>
<img src={user.profile_picture?.uri} />
{user.age}
{/* Render child component, passing the _fragment reference_: */}
<UsernameSection user={user} />
</div>
</>
);
}
module.exports = UserComponent;
這裡有幾點需要注意
UserComponent
既渲染UsernameSection
,又在其自身的graphql
片段宣告中包含UsernameSection
宣告的片段。UsernameSection
預期一個片段參考作為user
prop。如前所述,片段參考是 Relay 用來讀取片段定義中宣告的資料的物件;如您所見,子UsernameSection_user
片段本身僅宣告User
類型上的欄位,但我們需要知道要從哪個特定使用者讀取這些欄位;這就是片段參考對應的內容。換句話說,片段參考就像一個指向我們要從中讀取資料的特定類型實例的指標。- 請注意,在這種情況下,傳遞給
UsernameSection
的user
,即片段參考,實際上不包含子UsernameSection
元件宣告的任何資料;相反,UsernameSection
將使用片段參考來讀取它使用useFragment
在內部宣告的資料。 - 這表示父元件不會接收子元件選擇的資料(除非該父元件明確選擇相同的欄位)。同樣地,子元件不會接收其父元件選擇的資料(同樣地,除非子元件選擇相同的欄位)。
- 這可防止個別元件甚至意外地彼此具有隱含的依賴關係。如果不是這種情況,則修改元件可能會破壞其他元件!
- 這允許我們在本地推理我們的元件並修改它們,而無需擔心影響其他元件。
- 這稱為資料遮罩。
- 子系(即
UsernameSection
)預期的片段參考是讀取包含子片段的父片段的結果。在我們的特定範例中,這表示讀取包含...UsernameSection_user
的片段的結果將是UsernameSection
預期的片段參考。換句話說,透過useFragment
讀取片段而取得的資料也用作該片段中包含的任何子片段的片段參考。
將片段組合成查詢
Relay 中的片段允許宣告元件的資料依賴關係,但它們不能單獨提取。相反,它們需要直接或間接地包含在查詢中。這表示所有片段在渲染時都必須屬於一個查詢,換句話說,它們必須「根植」在某些查詢下。請注意,單個片段仍然可以被多個查詢包含,但是當渲染片段元件的特定實例時,它必須已包含在特定的查詢請求中。
若要提取和渲染包含片段的查詢,您可以像組合片段一樣組合它們,如組合片段部分所示
/**
* UserComponent.react.js
*
* Fragment Component
*/
import type {UserComponent_user$key} from 'UserComponent_user.graphql';
const React = require('React');
const {graphql, useFragment} = require('react-relay');
type Props = {
user: UserComponent_user$key,
};
function UserComponent(props: Props) {
const data = useFragment(
graphql`...`,
props.user,
);
return (...);
}
module.exports = UserComponent;
/**
* App.react.js
*
* Query Component
*/
import type {AppQuery} from 'AppQuery.graphql';
import type {PreloadedQuery} from 'react-relay';
const React = require('React');
const {graphql, usePreloadedQuery} = require('react-relay');
const UserComponent = require('./UserComponent.react');
type Props = {
appQueryRef: PreloadedQuery<AppQuery>,
}
function App({appQueryRef}) {
const data = usePreloadedQuery(
graphql`
query AppQuery($id: ID!) {
user(id: $id) {
name
# Include child fragment:
...UserComponent_user
}
}
`,
appQueryRef,
);
return (
<>
<h1>{data.user?.name}</h1>
{/* Render child component, passing the fragment reference: */}
<UserComponent user={data.user} />
</>
);
}
請注意
UserComponent
預期的片段參考是讀取包含其片段的父查詢的結果,在我們的例子中,這表示包含...UsernameSection_user
的查詢。換句話說,透過usePreloadedQuery
取得的data
也用作該查詢中包含的任何子片段的片段參考。- 如先前所述,所有片段在渲染時都必須屬於一個查詢,這表示所有片段元件都必須是查詢的後代。這保證您始終能夠為
useFragment
提供片段參考,方法是從使用usePreloadedQuery
讀取根查詢的結果開始。
這個頁面有用嗎?
透過以下方式協助我們使網站更好 回答幾個快速問題.