React with Inversify 使 useEffect 无限循环
React with Inversify makes useEffect infinite loop
我正在使用 CRA + TS 并集成了一个用于依赖注入的自定义挂钩 (Inversify)。这是我的代码:
// DI Provider
export const InversifyContext = React.createContext<{ container: Container | null }>({ container: null });
export const DiProvider: React.FC<Props> = (props) => {
return <InversifyContext.Provider value={{ container: props.container }}>{props.children}</InversifyContext.Provider>;
};
// Custom Hook
export function useInjection<T>(identifier: interfaces.ServiceIdentifier<T>): T {
const { container } = useContext(InversifyContext);
if (!container) {
throw new Error();
}
console.log("This is hook"); // This gets printed infinitely
return container.get<T>(identifier);
}
// Injectable Service
@injectable()
class MyService{
// some methods
}
// index.tsx
const container = new Container();
container.bind<MyService>("myService").to(MyService);
ReactDOM.render(
<DiProvider container={container}>
<MyComponent />,
document.getElementById("root")
);
// MyComponent.tsx
const MyComponent: React.FC = () => {
const myService = useInjection<MyService>("myService");
useEffect(() => {
myService.getData(); // Loop call
}, [myService]);
}
现在,当我调试代码时,我看到提供程序正在无限渲染,这导致组件重新渲染。
首先,您需要了解为什么会发生这种情况。
当您在 useEffect
挂钩中使用注入的服务作为依赖项 (您应该这样做),它会触发组件重新呈现,这将调用 useInjection
钩子和 MyService
的 new/updated 实例被 returned,因为实例被更改,useEffect
将再次被触发,这将以递归结束来电。
我同意您不应忽略 useEffect 依赖项。一个简单的解决方案是在挂钩中记忆服务。
所以你的 memoized 钩子将变成:
export function useInjection<T>(identifier: interfaces.ServiceIdentifier<T>): T {
const { container } = useContext(InversifyContext);
if (!container) {
throw new Error();
}
console.log("This is hook"); // This gets printed infinitely
return useMemo(() => container.get<T>(identifier), [container, identifier]);
}
您的挂钩现在将 return 服务实例的记忆版本。
我正在使用 CRA + TS 并集成了一个用于依赖注入的自定义挂钩 (Inversify)。这是我的代码:
// DI Provider
export const InversifyContext = React.createContext<{ container: Container | null }>({ container: null });
export const DiProvider: React.FC<Props> = (props) => {
return <InversifyContext.Provider value={{ container: props.container }}>{props.children}</InversifyContext.Provider>;
};
// Custom Hook
export function useInjection<T>(identifier: interfaces.ServiceIdentifier<T>): T {
const { container } = useContext(InversifyContext);
if (!container) {
throw new Error();
}
console.log("This is hook"); // This gets printed infinitely
return container.get<T>(identifier);
}
// Injectable Service
@injectable()
class MyService{
// some methods
}
// index.tsx
const container = new Container();
container.bind<MyService>("myService").to(MyService);
ReactDOM.render(
<DiProvider container={container}>
<MyComponent />,
document.getElementById("root")
);
// MyComponent.tsx
const MyComponent: React.FC = () => {
const myService = useInjection<MyService>("myService");
useEffect(() => {
myService.getData(); // Loop call
}, [myService]);
}
现在,当我调试代码时,我看到提供程序正在无限渲染,这导致组件重新渲染。
首先,您需要了解为什么会发生这种情况。
当您在 useEffect
挂钩中使用注入的服务作为依赖项 (您应该这样做),它会触发组件重新呈现,这将调用 useInjection
钩子和 MyService
的 new/updated 实例被 returned,因为实例被更改,useEffect
将再次被触发,这将以递归结束来电。
我同意您不应忽略 useEffect 依赖项。一个简单的解决方案是在挂钩中记忆服务。
所以你的 memoized 钩子将变成:
export function useInjection<T>(identifier: interfaces.ServiceIdentifier<T>): T {
const { container } = useContext(InversifyContext);
if (!container) {
throw new Error();
}
console.log("This is hook"); // This gets printed infinitely
return useMemo(() => container.get<T>(identifier), [container, identifier]);
}
您的挂钩现在将 return 服务实例的记忆版本。