状态更改时如何防止 运行 的 useQuery?

How to prevent useQuery for running when state changes?

我正在使用 React Apollo 从我的服务器获取数据。当我的页面加载时,我使用 useQuery 来检索数据。这很好用。问题是当我更改搜索表单时,这会更新导致不需要的重新呈现的状态,从而再次调用服务器。

我只想在页面加载和单击搜索按钮时调用服务器。

使用查询:

const { loading: loadingLessons, error: lessonsError, data: lessons } = useQuery(
 LESSON_BY_PARAMS,
    {
      variables: { findLessonsInput: searchParams },
    },
);

当我更改表单字段时,它会调用 updateFormField 来更新 redux 状态,从而导致重新呈现

<Autocomplete
  options={categories}
  getOptionLabel={(option: any) => option.label}
  inputValue={form.category}
  defaultValue={() => {
    const value = categories.find(option => option.label === form.category);
    return value;
  }}
  onChange={(event, value) => updateFormField('category', value?.label)}
  renderInput={params => (
    <TextField {...params} label="Category" variant="outlined" fullWidth />
  )}
/>

我正在使用反应钩子。

查看可用于完全跳过查询的 skip 选项。你可以这样做:

const [skip, setSkip] = React.useState(false)
const { loading, data } = useQuery(QUERY, { skip })

React.useEffect(() => {
  // check whether data exists
  if (!loading && !!data) {
    setSkip(true)
  }
}, [data, loading])

因此,一旦数据返回,您只需将 skip 选项设置为 true。如果你想发出请求,你应该处理搜索按钮上的 onClick(只需 setSkip(false))。

感谢@Vadim Sheremetov 的建议,但是我决定将 api 调用移动到 redux-thunk 函数:

当页面加载时,我发送一个动作,传递给它搜索参数和 apollo 客户端:

const client = useApolloClient();

useEffect(() => {
    loadLessons(searchParams, client);
}, [location.search]);

const mapDispatchToProps = dispatch => {
  return {
    loadLessons: (searchParams, client) =>
      dispatch(loadLessonsAction(searchParams, client)),
  };
};

该操作调用 redux thunk 函数,然后调度另一个更新状态的操作:

actions.ts:

export function loadLessonsAction(searchParams: any, client: ApolloClient<object>): 
any {
  return async function(dispatch) {
    try {
      const { data } = await client.query({
        query: LESSON_BY_PARAMS,
        variables: { findLessonsInput: searchParams },
      });
      dispatch(loadLessonsSuccessAction(data.lessonsByParams));
    } catch (error) {}
  };
}

export function loadLessonsSuccessAction(lessons: any[]): FilterPanelActionTypes {
  return {
    type: LOAD_LESSONS_SUCCESS,
    payload: lessons,
  };
}

reducer.ts:

case LOAD_LESSONS_SUCCESS: {
  return {
    ...state,
    lessons: action.payload.lessons,
    lessonCount: action.payload.count,
  };
}

如果您使用纯 apollo 客户端,您将失去 apollo 的一些功能。无需将 graphql 调用移动到 redux 操作中,您可以在 Redux 中使用选择器来防止组件重新加载或对服务器进行不必要的调用。

Selectors in Redux