useEffect 无限循环仅在测试时发生,否则不会发生 - 尽管使用 useReducer
useEffect infinite loop occurs only while testing, not otherwise - despite using useReducer
我正在尝试测试 useFetch 自定义挂钩。这是钩子:
import React from 'react';
function fetchReducer(state, action) {
if (action.type === `fetch`) {
return {
...state,
loading: true,
};
} else if (action.type === `success`) {
return {
data: action.data,
error: null,
loading: false,
};
} else if (action.type === `error`) {
return {
...state,
error: action.error,
loading: false,
};
} else {
throw new Error(
`Hello! This function doesn't support the action you're trying to do.`
);
}
}
export default function useFetch(url, options) {
const [state, dispatch] = React.useReducer(fetchReducer, {
data: null,
error: null,
loading: true,
});
React.useEffect(() => {
dispatch({ type: 'fetch' });
fetch(url, options)
.then((response) => response.json())
.then((data) => dispatch({ type: 'success', data }))
.catch((error) => {
dispatch({ type: 'error', error });
});
}, [url, options]);
return {
loading: state.loading,
data: state.data,
error: state.error,
};
}
这是测试
import useFetch from "./useFetch";
import { renderHook } from "@testing-library/react-hooks";
import { server, rest } from "../mocks/server";
function getAPIbegin() {
return renderHook(() =>
useFetch(
"http://fe-interview-api-dev.ap-southeast-2.elasticbeanstalk.com/api/begin",
{ method: "GET" },
1
)
);
}
test("fetch should return the right data", async () => {
const { result, waitForNextUpdate } = getAPIbegin();
expect(result.current.loading).toBe(true);
await waitForNextUpdate();
expect(result.current.loading).toBe(false);
const response = result.current.data.question;
expect(response.answers[2]).toBe("i think so");
});
// Overwrite mock with failure case
test("shows server error if the request fails", async () => {
server.use(
rest.get(
"http://fe-interview-api-dev.ap-southeast-2.elasticbeanstalk.com/api/begin",
async (req, res, ctx) => {
return res(ctx.status(500));
}
)
);
const { result, waitForNextUpdate } = getAPIbegin();
expect(result.current.loading).toBe(true);
expect(result.current.error).toBe(null);
expect(result.current.data).toBe(null);
await waitForNextUpdate();
console.log(result.current);
expect(result.current.loading).toBe(false);
expect(result.current.error).not.toBe(null);
expect(result.current.data).toBe(null);
});
只有在 运行 进行测试时,我才会不断收到错误消息:
“警告:超过最大更新深度。当组件在 useEffect 中调用 setState 时可能会发生这种情况,但 useEffect 没有依赖项数组,或者依赖项之一在每次渲染时都会发生变化。”
错误来自 TestHook:node_modules/@testing-library/react-hooks/lib/index.js:21:23)
在悬念
我不知道如何解决这个问题。 URL 和选项必须在依赖项数组中,并且 运行ning useEffect 不会更改它们,所以我不明白为什么会导致此循环。当我将它们从数组中取出时,测试成功了,但是当这些事情发生变化时,我需要再次 运行 的效果。
有什么想法吗?
试试这个。
function getAPIbegin(url, options) {
return renderHook(() =>
useFetch(url, options)
);
}
test("fetch should return the right data", async () => {
const url = "http://fe-interview-api-dev.ap-southeast-2.elasticbeanstalk.com/api/begin";
const options = { method: "GET" };
const { result, waitForNextUpdate } = getAPIbegin(url, options);
expect(result.current.loading).toBe(true);
await waitForNextUpdate();
expect(result.current.loading).toBe(false);
const response = result.current.data.question;
expect(response.answers[2]).toBe("i think so");
});
我没有使用过react-hooks-testing-library,但我的猜测是无论何时渲染React,都会重复调用发送到RenderHook
的回调,导致每次传递不同的选项时间.
我正在尝试测试 useFetch 自定义挂钩。这是钩子:
import React from 'react';
function fetchReducer(state, action) {
if (action.type === `fetch`) {
return {
...state,
loading: true,
};
} else if (action.type === `success`) {
return {
data: action.data,
error: null,
loading: false,
};
} else if (action.type === `error`) {
return {
...state,
error: action.error,
loading: false,
};
} else {
throw new Error(
`Hello! This function doesn't support the action you're trying to do.`
);
}
}
export default function useFetch(url, options) {
const [state, dispatch] = React.useReducer(fetchReducer, {
data: null,
error: null,
loading: true,
});
React.useEffect(() => {
dispatch({ type: 'fetch' });
fetch(url, options)
.then((response) => response.json())
.then((data) => dispatch({ type: 'success', data }))
.catch((error) => {
dispatch({ type: 'error', error });
});
}, [url, options]);
return {
loading: state.loading,
data: state.data,
error: state.error,
};
}
这是测试
import useFetch from "./useFetch";
import { renderHook } from "@testing-library/react-hooks";
import { server, rest } from "../mocks/server";
function getAPIbegin() {
return renderHook(() =>
useFetch(
"http://fe-interview-api-dev.ap-southeast-2.elasticbeanstalk.com/api/begin",
{ method: "GET" },
1
)
);
}
test("fetch should return the right data", async () => {
const { result, waitForNextUpdate } = getAPIbegin();
expect(result.current.loading).toBe(true);
await waitForNextUpdate();
expect(result.current.loading).toBe(false);
const response = result.current.data.question;
expect(response.answers[2]).toBe("i think so");
});
// Overwrite mock with failure case
test("shows server error if the request fails", async () => {
server.use(
rest.get(
"http://fe-interview-api-dev.ap-southeast-2.elasticbeanstalk.com/api/begin",
async (req, res, ctx) => {
return res(ctx.status(500));
}
)
);
const { result, waitForNextUpdate } = getAPIbegin();
expect(result.current.loading).toBe(true);
expect(result.current.error).toBe(null);
expect(result.current.data).toBe(null);
await waitForNextUpdate();
console.log(result.current);
expect(result.current.loading).toBe(false);
expect(result.current.error).not.toBe(null);
expect(result.current.data).toBe(null);
});
只有在 运行 进行测试时,我才会不断收到错误消息: “警告:超过最大更新深度。当组件在 useEffect 中调用 setState 时可能会发生这种情况,但 useEffect 没有依赖项数组,或者依赖项之一在每次渲染时都会发生变化。”
错误来自 TestHook:node_modules/@testing-library/react-hooks/lib/index.js:21:23) 在悬念
我不知道如何解决这个问题。 URL 和选项必须在依赖项数组中,并且 运行ning useEffect 不会更改它们,所以我不明白为什么会导致此循环。当我将它们从数组中取出时,测试成功了,但是当这些事情发生变化时,我需要再次 运行 的效果。
有什么想法吗?
试试这个。
function getAPIbegin(url, options) {
return renderHook(() =>
useFetch(url, options)
);
}
test("fetch should return the right data", async () => {
const url = "http://fe-interview-api-dev.ap-southeast-2.elasticbeanstalk.com/api/begin";
const options = { method: "GET" };
const { result, waitForNextUpdate } = getAPIbegin(url, options);
expect(result.current.loading).toBe(true);
await waitForNextUpdate();
expect(result.current.loading).toBe(false);
const response = result.current.data.question;
expect(response.answers[2]).toBe("i think so");
});
我没有使用过react-hooks-testing-library,但我的猜测是无论何时渲染React,都会重复调用发送到RenderHook
的回调,导致每次传递不同的选项时间.