在react-apollo Query中使用变量的技术实现咨询
Hey there! Since you're already familiar with using the graphql HOC to fetch data in your React Native Home component, let's dive into how to handle variables and optimize data mapping when using Apollo Client's <Query> component (or the modern useQuery hook, which is even more convenient for function components).
1. Variable Configuration in the <Query> Component
First, let's adjust your query to explicitly declare variables—this is best practice and makes your query reusable across different components or contexts:
// Define your query with a variable declaration const GET_NEARBY_STORIES = gql` query GetNearbyStories($geoHash: String!) { getStoriesNearbyByGeoHash(geoHash: $geoHash) { id } } `;
The $geoHash: String! syntax tells Apollo we expect a required string variable named geoHash for this query.
Static Variables
If your variable is static (like your mockGeoHash), pass it directly via the variables prop:
import { Query } from 'react-apollo'; // Inside your Home component's render method <Query query={GET_NEARBY_STORIES} variables={{ geoHash: mockGeoHash }} > {({ loading, error, data }) => { // Handle loading/error states first if (loading) return <Text>Loading nearby stories...</Text>; if (error) return <Text>Oops! {error.message}</Text>; // Map data to your desired format const storiesNearby = data.getStoriesNearbyByGeoHash.map(story => ({ id: story.id })); return <StoryList stories={storiesNearby} />; }} </Query>
Dynamic Variables
If you need to update the variable dynamically (e.g., based on user location or component state), pull it directly from your component's state or props:
// For class components <Query query={GET_NEARBY_STORIES} variables={{ geoHash: this.state.userGeoHash }} > {/* ... render prop logic ... */} </Query> // For function components (using useState) const [userGeoHash, setUserGeoHash] = useState('8k'); <Query query={GET_NEARBY_STORIES} variables={{ geoHash: userGeoHash }} > {/* ... render prop logic ... */} </Query>
2. Optimizing Data Mapping
Let's make your data mapping more efficient, maintainable, and less prone to unnecessary re-renders:
Extract Mapping Logic to a Pure Function
Avoid repeating inline mapping logic by extracting it to a reusable pure function. This makes updates easier and keeps your component code clean:
// Reusable mapper function (can live in a utils file too!) const mapStoryToListItem = (story) => ({ id: story.id, // Add other fields here if you need them later }); // Use it in your Query component const storiesNearby = data.getStoriesNearbyByGeoHash.map(mapStoryToListItem);
Memoize Mapped Data to Prevent Unnecessary Re-renders
If you're using function components, use React's useMemo hook to cache the mapped array. This ensures the array reference only changes when the source data updates, preventing child components from re-rendering unnecessarily:
import { useMemo } from 'react'; // Inside the Query's render prop or useQuery hook const storiesNearby = useMemo(() => { return data.getStoriesNearbyByGeoHash.map(mapStoryToListItem); }, [data.getStoriesNearbyByGeoHash]); // Only re-run if the source array changes
Keep Queries Targeted
You're already doing this well, but it's worth emphasizing: only request the fields you need in your GraphQL query. This reduces data transfer size and eliminates the need to filter out unused fields during mapping.
Reuse Loading/Error States
Create a reusable wrapper component to avoid duplicating loading/error logic across your app. This cuts down on boilerplate and ensures consistent UI for all query-driven components:
const QueryWrapper = ({ query, variables, children }) => ( <Query query={query} variables={variables}> {({ loading, error, data }) => { if (loading) return <LoadingSpinner />; if (error) return <ErrorBanner message={error.message} />; return children(data); }} </QueryWrapper> ); // Usage in Home component <QueryWrapper query={GET_NEARBY_STORIES} variables={{ geoHash: mockGeoHash }}> {(data) => { const storiesNearby = data.getStoriesNearbyByGeoHash.map(mapStoryToListItem); return <StoryList stories={storiesNearby} />; }} </QueryWrapper>
3. Bonus: Use the useQuery Hook (Modern Approach)
For function components, Apollo's useQuery hook is more concise than the <Query> render prop component. Here's how to refactor your code to use it:
import { useQuery, gql } from '@apollo/client'; // Note: Newer Apollo versions use @apollo/client const GET_NEARBY_STORIES = gql` query GetNearbyStories($geoHash: String!) { getStoriesNearbyByGeoHash(geoHash: $geoHash) { id } } `; const mapStoryToListItem = (story) => ({ id: story.id }); const Home = () => { const { loading, error, data } = useQuery(GET_NEARBY_STORIES, { variables: { geoHash: mockGeoHash }, }); if (loading) return <Text>Loading...</Text>; if (error) return <Text>Error: {error.message}</Text>; const storiesNearby = useMemo(() => data.getStoriesNearbyByGeoHash.map(mapStoryToListItem), [data.getStoriesNearbyByGeoHash] ); return <StoryList stories={storiesNearby} />; }; export default Home;
内容的提问来源于stack exchange,提问作者reggie3

