【问题标题】:How to prevent useQuery for running when state changes?状态变化时如何防止 useQuery 运行?
【发布时间】:2023-03-08 20:49:01
【问题描述】:

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

我正在使用反应钩子。

【问题讨论】:

    标签: reactjs react-redux react-apollo


    【解决方案1】:

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

    Selectors in Redux

    【讨论】:

      【解决方案2】:

      感谢@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,
        };
      }
      

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          猜你喜欢
          • 2021-02-22
          • 2012-01-31
          • 1970-01-01
          • 2015-01-10
          • 1970-01-01
          • 2023-03-06
          • 1970-01-01
          相关资源
          最近更新 更多