React中Apollo Boost两类问题:变量变更不自动重取与外部触发重取
Hey there! Let's break down your two Apollo Boost questions one by one, using your GalleryPage scenario as context:
a) 为什么Apollo不会在变量变更时自动重新获取数据?
Apollo's Query component relies on shallow comparison of the variables prop to decide whether to re-run the query. The most common reason it doesn't trigger automatically is that your filter object's reference hasn't changed—even if you modified its internal values.
For example, if you update your state like this (which mutates the original object):
// ❌ Bad: Modifies the existing filters object directly this.state.filters.brands.push(2); this.setState({ filters: this.state.filters });
Apollo won't detect a change because the filters object still points to the same reference in memory.
Fix: Always return a new object reference
When updating your filters state, create a new object/array instead of mutating the old one. This lets Apollo's shallow comparison pick up the change:
// ✅ Good: Creates a new filters object with updated values this.setState(prevState => ({ filters: { ...prevState.filters, brands: [...prevState.filters.brands, 2] // New array for brands } }));
Then pass this updated state directly to your Query component's variables prop:
<Query query={YOUR_GALLERY_QUERY} variables={{ filters: this.state.filters }} > {/* Render prop content */} </Query>
Also double-check that your GraphQL query actually uses the $filters variable—if the query doesn't depend on those variables, changing them won't trigger a re-fetch.
b) 如何在Query组件外部调用refetch方法?
There are two straightforward ways to do this in a class component:
Method 1: Save the refetch method to your component instance
You can capture the refetch function provided by the Query component's render prop and store it on your class instance. Then you can call it from anywhere in your parent component:
class GalleryPage extends Component { constructor () { super(); this.state = { filters: { brands: [1, 3], filetypes: [4, 5, 6] }, }; this.galleryRefetch = null; // Hold refetch reference here } handleFilterUpdate = () => { // Call refetch whenever you need to (e.g., after updating filters) if (this.galleryRefetch) { this.galleryRefetch({ filters: this.state.filters }); } }; render() { return ( <div> {/* Example: Button to trigger refetch */} <button onClick={this.handleFilterUpdate}>Apply Filters & Refresh</button> <Query query={YOUR_GALLERY_QUERY} variables={{ filters: this.state.filters }} > {({ loading, error, data, refetch }) => { // Save refetch to component instance this.galleryRefetch = refetch; if (loading) return <p>Loading...</p>; if (error) return <p>Oops, something went wrong!</p>; return <GalleryComponent data={data} />; }} </Query> </div> ); } }
Method 2: Use Apollo Client's direct query method
If you wrap your component with the withApollo higher-order component, you can access the Apollo Client instance directly and run queries manually:
import { withApollo } from 'react-apollo'; class GalleryPage extends Component { // ... constructor and state handleFilterUpdate = async () => { try { const result = await this.props.client.query({ query: YOUR_GALLERY_QUERY, variables: { filters: this.state.filters }, // Optional: Set fetchPolicy if you need fresh data fetchPolicy: 'network-only' }); // Handle the returned data here if needed } catch (error) { // Handle errors console.error('Query failed:', error); } }; // ... render method } // Wrap component to inject Apollo Client export default withApollo(GalleryPage);
Note: This method doesn't automatically update the Query component's cached data unless you specify the right fetch policy, so use it only if you need full manual control.
内容的提问来源于stack exchange,提问作者Sebastian

