Apollo 클라이언트에서 계산된 로컬 전용 필드
13571 단어 graphqltypescriptreactjavascript
Apollo 클라이언트의 중요한 기능 중 하나는 로컬 전용 필드입니다. 이러한 필드는 애플리케이션이 서버로 보낸 작업에서 수정된 다음 계산되어 서버 응답에 추가되어 최종 결과를 생성합니다. Apollo 문서는 로컬 상태 관리를 위해 이 기능을 활용하는 방법을 명확하게 설명하지만 작업 결과의 다른 필드에서만 순수한 로컬 전용 필드를 파생시키는 방법에 대해서는 명확하지 않습니다.
A (인위적인) 예
현재 사용자를 쿼리하는 작업이 있다고 가정합니다.
const USER_QUERY = gql`
query User {
user {
id
firstName
lastName
department {
id
name
}
}
}
`;
일부
UserProfile
구성요소에서 이 작업의 결과를 사용하여 John Doe - Engineering team
형식으로 표시 이름을 렌더링합니다.const UserProfile = () => {
const { data } = useQuery(USER_QUERY);
const displayName = `${data.user.firstName} ${data.user.lastName} - ${data.user.department.name} team`;
return (
<div>
<ProfilePicture />
<p>{displayName}</p>
<ContactInfo />
</div>
);
}
시간이 지남에 따라 애플리케이션 전체의 여러 위치에서 동일한
displayName
형식을 사용하고 매번 동일한 로직을 복제하게 됩니다.const BlogPost = () => {
const { data } = useQuery(USER_QUERY);
const displayName = `${data.user.firstName} ${data.user.lastName} - ${data.user.department.name} team`;
return (
<div>
<BlogTitle />
<p>Written by {displayName}</p>
<BlogContent />
</div>
);
}
우리는 애플리케이션 전체에서 이 형식화된 이름을 재사용하는 최선의 방법을 고려합니다. 우리의 첫 번째 생각은 서버측 리졸버일 수 있지만 이것이 항상 실현 가능한 것은 아닙니다. 예를 들어 현지 시간과 같은 클라이언트측 데이터를 사용하거나 계산에서 연합하기 어려운 다양한 하위 그래프의 필드를 사용할 수 있습니다. 우리의 다음 생각은 React 구성 요소이지만 이것도 잘 작동하지 않습니다. displayName에 대해 일관된 형식을 원하지만 컨텍스트에 따라 사용법이나 스타일이 상당히 다를 수 있습니다. 그럼 훅은요? 쿼리 및 디스플레이 논리를 캡슐화하는
useDisplayName
후크일까요? 더 좋지만 우아하지 않습니다. 동일한 구성 요소에서 useQuery
및 useDisplayName
후크를 반복해서 호출하게 될 것입니다. 우리가 정말 원하는 것은 쿼리 결과에서 파생된 논리가 아니라 쿼리 결과에 통합된 논리입니다.솔루션
로컬 전용 필드의 첫 번째 요구 사항은 캐시에
read
함수가 있는 해당 필드 정책입니다. (기술적으로는 캐시에서 읽고 쓰기 위해 필드 정책을 생략할 수 있지만 다른 게시물을 위해 저장하겠습니다.)const cache = new InMemoryCache({
typePolicies: {
User: {
fields: {
displayName: {
read(_) {
return null; // We'll implement this soon
}
}
}
}
}
});
읽기 함수의 첫 번째 인수는 기존 필드 값이며 정의에 따라 아직 존재하지 않기 때문에 로컬 전용 필드에 대해 정의되지 않습니다.
로컬 전용 필드에 대한 다른 요구 사항은
@client
지시문을 사용하여 작업에 추가하는 것입니다. 이렇게 하면 Apollo 클라이언트가 서버 요청에서 필드를 제거한 다음 read
함수로 계산된 값을 사용하여 결과로 복원하도록 지시합니다.const USER_QUERY = gql`
query User {
user {
id
firstName
lastName
displayName @client
department {
id
name
}
}
}
`;
이제 이 필드는
data
후크에서 반환한 useQuery
필드에 포함되지만 물론 지금은 항상 null을 반환합니다. 원하는 형식에는 서버 응답의 세 필드, 즉 사용자firstName
및 lastName
및 부서name
가 필요합니다. 여기서 요령은 readField
함수의 두 번째 "옵션"인수에서 제공하는 도우미인 read
입니다. 이 헬퍼는 기본적으로 필드의 부모 개체에서 또는 두 번째 인수로 포함된 경우 다른 개체에서 요청된 값(존재하는 경우)을 제공합니다. 이 도우미는 또한 정규화된 참조를 해결하여 호출을 편리하게 중첩readField
할 수 있도록 합니다. 로컬 전용 필드가 종속된 필드를 포함하도록 작업을 강제할 수 없으므로 readField
항상 정의되지 않은 값을 반환할 가능성이 있습니다(null을 허용하지 않는 필드인 경우에도).const cache = new InMemoryCache({
typePolicies: {
User: {
fields: {
displayName: {
read(_, { readField }) {
// References the parent User object by default
const firstName = readField("firstName");
const lastName = readField("lastName");
// References the Department object of the parent User object
const departmentName = readField("name", readField("department"));
// We can't guarantee these fields were included in the operation
if (!firstName || !lastName || !departmentName) {
return "A Valued Team Member";
}
return `${data.user.firstName} ${data.user.lastName} - ${data.user.department.name} team`;
}
}
}
}
}
});
이제 응용 프로그램의 어느 곳에서나 이 형식이 지정된 표시 이름을 사용하는 것이 간단합니다. 쿼리 데이터의 또 다른 필드일 뿐입니다!
const BlogPost = () => {
const { data } = useQuery(USER_QUERY);
return (
<div>
<BlogTitle />
<p>Written by {data.displayName}</p>
<BlogContent />
</div>
);
}
보너스: GraphQL 코드 생성이 있는 로컬 전용 필드
graphql-codegen
를 사용하는 경우 로컬 전용 필드를 포함하는 것은 간단합니다(사용하지 않는 경우 시작하기도 매우 쉽습니다.). 클라이언트 측 스키마 파일에서 로컬 전용 필드를 추가할 유형을 확장하기만 하면 됩니다.const typeDefs = gql`
extend type User {
# Don't forget to return a default value
# in the event a field dependency is undefined
# if the local-only field is non-nullable
displayName: String!
}
`;
Reference
이 문제에 관하여(Apollo 클라이언트에서 계산된 로컬 전용 필드), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ef/computed-local-only-fields-in-apollo-client-3714텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)