You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apollo 2.1多查询/突变组件使用求助:依赖查询与多突变问题

Hey there! Let's break down your Apollo 2.1 questions step by step—these are really common scenarios when building with GraphQL and React, so I’ve got you covered.

1. Handling Dependent GraphQL Queries (One Depends on the Previous Result)

In Apollo 2.1, the cleanest approach for dependent queries is to nest Query components. Since each Query waits for its data to resolve before rendering its children, you can safely pass the first query's result as variables to the second.

Here's a concrete example: let's say you first fetch a user's ID, then use that ID to pull their associated orders.

import { Query } from 'react-apollo';
import gql from 'graphql-tag';

// First query: Fetch current user's ID
const GET_CURRENT_USER = gql`
  query GetCurrentUser {
    currentUser {
      id
    }
  }
`;

// Second query: Fetch orders using a user ID variable
const GET_USER_ORDERS = gql`
  query GetUserOrders($userId: ID!) {
    userOrders(userId: $userId) {
      id
      total
      date
    }
  }
`;

function UserOrders() {
  return (
    <Query query={GET_CURRENT_USER}>
      {({ loading: userLoading, error: userError, data: userData }) => {
        if (userLoading) return <p>Loading user data...</p>;
        if (userError) return <p>Oops, failed to load user: {userError.message}</p>;

        // Once we have the user ID, pass it to the nested Query
        const userId = userData.currentUser.id;
        return (
          <Query query={GET_USER_ORDERS} variables={{ userId }}>
            {({ loading: ordersLoading, error: ordersError, data: ordersData }) => {
              if (ordersLoading) return <p>Loading your orders...</p>;
              if (ordersError) return <p>Failed to load orders: {ordersError.message}</p>;

              return (
                <div>
                  <h3>Your Recent Orders</h3>
                  <ul>
                    {ordersData.userOrders.map(order => (
                      <li key={order.id}>
                        Order #{order.id} - ${order.total} ({order.date})
                      </li>
                    ))}
                  </ul>
                </div>
              );
            }}
          </Query>
        );
      }}
    </Query>
  );
}

Key notes:

  • Handle loading/error states for both queries separately to keep the UI responsive and user-friendly.
  • The inner Query only renders once the outer query has successfully returned data—so you’ll never pass an undefined userId as a variable.
  • For longer dependency chains, you can keep nesting Query components as needed. If you ever upgrade beyond Apollo 2.1, useQuery hooks offer more concise ways to handle this, but nested components are the go-to for your current version.
2. Adding Multiple Mutations to a Component with an Existing Query

Adding multiple Mutation components to a Query-based component is totally straightforward—you can nest them inside the Query's render prop or place them alongside each other. Each Mutation exposes its own mutate function that you can trigger with user actions (like button clicks).

Let's extend the previous example to add two mutations: one to update an order's status, and another to delete an order.

import { Query, Mutation } from 'react-apollo';
import gql from 'graphql-tag';

// Reuse the GET_CURRENT_USER and GET_USER_ORDERS queries from above

// Mutation 1: Update an order's status
const UPDATE_ORDER_STATUS = gql`
  mutation UpdateOrderStatus($orderId: ID!, $status: String!) {
    updateOrderStatus(orderId: $orderId, status: $status) {
      id
      status
    }
  }
`;

// Mutation 2: Delete an order
const DELETE_ORDER = gql`
  mutation DeleteOrder($orderId: ID!) {
    deleteOrder(orderId: $orderId) {
      id
    }
  }
`;

function UserOrders() {
  return (
    <Query query={GET_CURRENT_USER}>
      {({ loading: userLoading, error: userError, data: userData }) => {
        if (userLoading) return <p>Loading user data...</p>;
        if (userError) return <p>Oops, failed to load user: {userError.message}</p>;

        const userId = userData.currentUser.id;
        return (
          <Query query={GET_USER_ORDERS} variables={{ userId }}>
            {({ loading: ordersLoading, error: ordersError, data: ordersData, refetch }) => {
              if (ordersLoading) return <p>Loading your orders...</p>;
              if (ordersError) return <p>Failed to load orders: {ordersError.message}</p>;

              // Use `refetch` to refresh the order list after mutations
              return (
                <div>
                  <h3>Your Recent Orders</h3>
                  <ul>
                    {ordersData.userOrders.map(order => (
                      <li key={order.id}>
                        <div>
                          Order #{order.id} - ${order.total} ({order.date})
                          <span>Status: {order.status}</span>
                        </div>

                        {/* Mutation 1: Mark order as shipped */}
                        <Mutation 
                          mutation={UPDATE_ORDER_STATUS}
                          onCompleted={() => refetch()} // Refresh orders after success
                        >
                          {(updateStatus, { error: updateError }) => (
                            <>
                              <button onClick={() => updateStatus({
                                variables: { orderId: order.id, status: 'Shipped' }
                              })}>
                                Mark as Shipped
                              </button>
                              {updateError && <p className="error">Failed to update status: {updateError.message}</p>}
                            </>
                          )}
                        </Mutation>

                        {/* Mutation 2: Delete the order */}
                        <Mutation 
                          mutation={DELETE_ORDER}
                          onCompleted={() => refetch()} // Refresh orders after deletion
                        >
                          {(deleteOrder, { error: deleteError }) => (
                            <>
                              <button onClick={() => {
                                if (window.confirm('Are you sure you want to delete this order?')) {
                                  deleteOrder({ variables: { orderId: order.id } });
                                }
                              }}>
                                Delete Order
                              </button>
                              {deleteError && <p className="error">Failed to delete order: {deleteError.message}</p>}
                            </>
                          )}
                        </Mutation>
                      </li>
                    ))}
                  </ul>
                </div>
              );
            }}
          </Query>
        );
      }}
    </Query>
  );
}

Key points:

  • Each Mutation component is independent—you can add as many as you need in the same component.
  • Use the onCompleted prop to call refetch() on the Query after a mutation succeeds. This ensures the order list updates to reflect the new state.
  • The Mutation's render prop gives you access to the mutate function (we named them updateStatus and deleteOrder for clarity) which you can tie to user interactions like button clicks.
  • Don’t forget to handle mutation errors by destructuring the error object from the Mutation's render prop.

内容的提问来源于stack exchange,提问作者brunodahora

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:50:24