如何在状态更改时阻止 useQuery 运行?

IT技术 reactjs react-redux react-apollo
2021-05-12 14:33:09

我正在使用 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 />
  )}
/>

我正在使用react-hooks。

3个回答

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

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])

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

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

Redux 中的选择器

感谢@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 函数,该函数然后调度另一个更新状态的动作:

动作.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,
  };
}

减速器.ts:

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