類型發射
作為其正常工作的一部分,Relay 編譯器將為您選擇的語言發射類型資訊,以幫助您編寫類型安全應用程式碼。這些類型包含在 relay-compiler
產生的工件中,用於描述您的操作和片段。
操作變數
用於查詢、變異或訂閱操作的變數物件的形狀。
在此範例中,發射的類型資訊將要求變數物件包含一個具有非空字串的 artistID
鍵。
- Flow
- TypeScript
/**
* export type ExampleQuery$variables = {
* +artistID: string,
* }
* export type ExampleQuery$data = {
* +artist: {
* +name: ?string,
* }
* }
* export type ExampleQuery = {
* +variables: ExampleQuery$variables,
* +response: ExampleQuery$data,
* }
*/
const data = useLazyLoadQuery(
graphql`
query ExampleQuery($artistID: ID!) {
artist(id: $artistID) {
name
}
}
`,
// variables are expected to be of type ExampleQuery$variables
{artistID: 'banksy'},
);
/**
* export type ExampleQuery$variables = {
* readonly artistID: string
* }
* export type ExampleQuery$data = {
* readonly artist?: {
* readonly name?: string
* }
* }
* export type ExampleQuery = {
* readonly variables: ExampleQuery$variables
* readonly response: ExampleQuery$data
* }
*/
const data = useLazyLoadQuery(
graphql`
query ExampleQuery($artistID: ID!) {
artist(id: $artistID) {
name
}
}
`,
// variables are expected to be of type ExampleQuery$variables
{artistID: 'banksy'},
);
操作與片段資料
在操作或片段中選取的資料形狀,遵循資料遮罩規則。也就是說,排除任何由片段擴展選取的資料。
在此範例中,發射的類型資訊描述了 useLazyLoadQuery
(或 usePreloadedQuery
) 返回的回應資料。
- Flow
- TypeScript
/**
* export type ExampleQuery$variables = {
* +artistID: string,
* }
* export type ExampleQuery$data = {
* +artist: {
* +name: ?string,
* }
* }
* export type ExampleQuery = {
* +variables: ExampleQuery$variables,
* +response: ExampleQuery$data,
* }
*/
// data is of type ExampleQuery$data
const data = useLazyLoadQuery(
graphql`
query ExampleQuery($artistID: ID!) {
artist(id: $artistID) {
name
}
}
`,
{artistID: 'banksy'},
);
return props.artist && <div>{props.artist.name} is great!</div>
/**
* export type ExampleQuery$variables = {
* readonly artistID: string
* }
* export type ExampleQuery$data = {
* readonly artist?: {
* readonly name?: string
* }
* }
* export type ExampleQuery = {
* readonly variables: ExampleQuery$variables
* readonly response: ExampleQuery$data
* }
*/
// data is of type ExampleQuery$data
const data = useLazyLoadQuery(
graphql`
query ExampleQuery($artistID: ID!) {
artist(id: $artistID) {
name
}
}
`,
{artistID: 'banksy'},
);
return props.artist && <div>{props.artist.name} is great!</div>
類似地,在此範例中,發射的類型資訊描述了 prop 的類型,以匹配 useFragment
期望接收的片段參考類型。
- Flow
- TypeScript
/**
* export type ExampleFragmentComponent_artist$data = {
* +name: string
* }
*
* export type ExampleFragmentComponent_artist$key = { ... }
*/
import type { ExampleFragmentComponent_artist$key } from "__generated__/ExampleFragmentComponent_artist.graphql"
type Props = {
artist: ExampleFragmentComponent_artist$key,
};
export default ExampleFragmentComponent(props) {
// data is of type ExampleFragmentComponent_artist$data
const data = useFragment(
graphql`
fragment ExampleFragmentComponent_artist on Artist {
biography
}
`,
props.artist,
);
return <div>About the artist: {props.artist.biography}</div>;
}
/**
* export type ExampleFragmentComponent_artist$data = {
* readonly name: string
* }
*
* export type ExampleFragmentComponent_artist$key = { ... }
*/
import { ExampleFragmentComponent_artist$key } from "__generated__/ExampleFragmentComponent_artist.graphql"
interface Props {
artist: ExampleFragmentComponent_artist$key,
};
export default ExampleFragmentComponent(props: Props) {
// data is of type ExampleFragmentComponent_artist$data
const data = useFragment(
graphql`
fragment ExampleFragmentComponent_artist on Artist {
biography
}
`,
props.artist,
);
return <div>About the artist: {props.artist.biography}</div>;
}
片段參考
在資料遮罩中描述的不透明識別符號,子容器期望從其父容器接收,它代表子容器在父容器片段內的片段擴展。
考慮一個組合上述片段元件範例的元件。在此範例中,子元件發射的類型資訊會收到一個稱為片段參考的唯一不透明識別符號類型,該類型資訊是在父元件片段中擴展子元件片段的位置發射的。因此,確保子元件的片段被擴展到父元件的片段中,且在執行時將正確的片段參考傳遞給子元件。
- Flow
- TypeScript
import { ExampleFragmentComponent } from "./ExampleFragmentComponent"
/**
* import type { ExampleFragmentComponent_artist$fragmentType } from "ExampleFragmentComponent_artist.graphql";
*
* export type ExampleQuery$data = {
* +artist: ?{
* +name: ?string,
* +$fragmentSpreads: ExampleFragmentComponent_artist$fragmentType,
* }
* };
* export type ExampleQuery$variables = {
* +artistID: string,
* }
* export type ExampleQuery = {
* +variables: ExampleQuery$variables,
* +response: ExampleQuery$data,
* }
*/
// data is of type ExampleQuery$data
const data = useLazyLoadQuery(
graphql`
query ExampleQuery($artistID: ID!) {
artist(id: $artistID) {
name
...ExampleFragmentComponent_artist
}
}
`,
{artistID: 'banksy'},
);
// Here only `data.artist.name` is directly visible,
// the marker prop $fragmentSpreads indicates that `data.artist`
// can be used for the component expecting this fragment spread.
return <ExampleFragmentComponent artist={data.artist} />;
import { ExampleFragmentComponent } from "./ExampleFragmentComponent"
/**
* import { ExampleFragmentComponent_artist$fragmentType } from "ExampleFragmentComponent_artist.graphql";
*
* export type ExampleQuery$data = {
* readonly artist?: {
* readonly name: ?string,
* readonly " $fragmentSpreads": ExampleFragmentComponent_artist$fragmentType
* }
* }
* export type ExampleQuery$variables = {
* readonly artistID: string
* }
* export type ExampleQuery = {
* readonly variables: ExampleQuery$variables
* readonly response: ExampleQuery$data
* }
*/
// data is of type ExampleQuery$data
const data = useLazyLoadQuery(
graphql`
query ExampleQuery($artistID: ID!) {
artist(id: $artistID) {
name
...ExampleFragmentComponent_artist
}
}
`,
{artistID: 'banksy'},
);
// Here only `data.artist.name` is directly visible,
// the marker prop $fragmentSpreads indicates that `data.artist`
// can be used for the component expecting this fragment spread.
return <ExampleFragmentComponent artist={data.artist} />;
單一工件目錄
需要注意的一個重要事項是,預設情況下,不會發射嚴格的片段參考類型資訊,而是將它們鍵入為 any
,並且允許您將任何資料傳遞給子元件。
要啟用此功能,您必須透過在編譯器配置中指定 artifactDirectory
,告訴編譯器將所有工件儲存在單一目錄中
{
// package.json
"relay": {
"artifactDirectory": "./src/__generated__",
...
},
...
}
…並另外在您的 .babelrc
配置中通知 babel 外掛程式在哪裡尋找工件
{
"plugins": [
["relay", { "artifactDirectory": "./src/__generated__" }]
]
}
建議在您的模組解析配置中為此目錄設定別名,這樣您就不需要在原始程式碼檔案中指定相對路徑。這也是在上述範例中所做的,其中工件是從 __generated__
別名匯入的,而不是像 ../../../../__generated__
這樣的相對路徑。
背景資訊
原因是 relay-compiler
及其工件發射是無狀態的。這表示它不會追蹤原始程式碼檔案的位置以及編譯器先前在磁碟上儲存的隨附工件的位置。因此,如果編譯器要發射嘗試從其他工件匯入片段參考類型的工件,編譯器會
- 首先需要知道該其他工件在磁碟上的哪個位置;
- 並在其他工件變更磁碟上的位置時更新匯入。
Facebook 使用一個名為Haste的模組系統,其中所有原始程式碼檔案都視為在一個平面命名空間中。這表示匯入宣告不需要指定另一個模組的路徑,因此編譯器永遠不需要考慮上述問題。也就是說,匯入只需要指定模組檔案名稱的 basename,而 Haste 會在匯入時負責實際尋找正確的模組。然而,在 Facebook 之外,Haste 模組系統的使用是不存在的,也不鼓勵使用,因此決定不匯入片段參考類型,而是將它們鍵入為 any
。
最簡單來說,我們可以將 Haste 視為一個包含所有模組檔案的單一目錄,因此所有模組匯入都可以使用相對同級路徑安全地匯入。這就是單一工件目錄功能實現的目標。與將工件與其原始程式碼檔案共置不同,所有工件都儲存在單一目錄中,允許編譯器發射片段參考類型的匯入。
此頁面是否有用?
透過以下方式幫助我們讓網站變得更好 回答幾個快速問題.