在 React 函数组件外部使用变量是一种反模式吗?
Is it an anti-pattern to use variables the outside of React function component?
下面的 case 是 React 中的反模式吗?
出于某些原因,变量和函数可能会在 React 函数组件之外声明。例如,计时器 ID 和其他可以使用如下:
import React from "react";
const myFunc = () => { // no purpose
/*some codes*/
}
let myBool = false; // no purpose
let timerId = 0;
const MyComponent = () => {
const [name, setName] = useState("");
/* some codes */
useEffect(() => {
timerId = setTimeout(() => {
/* some codes */
}, 1000);
return () => clearTimeout(timerId);
}, []);
return (
<div>Hello world</div>
);
}
export default MyComponent;
对于可能改变的变量,比如在你的例子中,是的,它很可能被认为是一个问题,因为你不能指望任何使用具有一致效果的组件,因为它不是纯粹的,而是取决于外部变量的当前状态(而不是 React 状态)。
例如,如果您有一个 MyComponent
,后来您决定向您的站点添加另一个部分,该部分也使用了 MyComponent
,并且同时呈现了这两个部分,那么您现有的代码将导致问题,因为两个组件将共享相同的 timerId
变量 - 第一个渲染的组件将丢失其 timerId
。 (只有第二个要渲染的组件才能清除持久性外部 timerId
)
在这些情况下,组件内部使用的值属于该组件的给定实例,而不是整个应用程序,您应该使用状态(与 useState
) 而不是外部变量。
一般来说,使用外部标识符并不总是一个坏主意,但恰恰相反,对于不会改变并且对抽象有用的常量值,例如 URL、API 键, 分离非 React 函数,等等。以下类型的模式并不少见:
import { makeApiCall } from './makeApiCall';
export const SomeComponent = () => {
// ...more code here dealing with state
const handleClick = () => {
makeApiCall()
.then(handleSuccess)
.then(handleFail);
};
return (
<button onClick={handleClick}>click</button>
);
};
这样做不是犯罪。但在你这样做之前,想想你为什么要这样做。
如果你想像export { MyComponent, myFunc, timerId, myBool};
一样将这些变量连同组件一起暴露给外界,那么使用这种模式是有意义的。否则最好在功能组件本身内部声明 variable/function。
是的,这是一个反模式。 IMO 功能组件背后的整个想法是使组件纯净。使 React 函数组件变得纯净,使其更易于预测,您的输出仅由函数的输入决定。在函数范围之外使用变量会使函数不再纯粹。使用纯函数有几个好处。我强烈推荐使用纯功能组件。
是的,它被认为是反模式,您不能只在组件内定义这些变量,因为值将在重新呈现组件时重新初始化。
我们在 React 中有 ref 对象来实现这一点:
import React from "react";
const myFunc = () => { // no purpose
/*some codes*/
}
const MyComponent = () => {
const [name, setName] = useState("");
const myBool = useRef(false);
const timerId = useRef(0);
/* some codes */
useEffect(() => {
timerId.current = setTimeout(() => {
/* some codes */
}, 1000);
return () => clearTimeout(timerId.current);
}, []);
return (
<div>Hello world</div>
);
}
export default MyComponent;
myBool
和 timerId
不会在重新渲染时改变,您可以根据需要改变这些对象。您可以阅读更多 here.
下面的 case 是 React 中的反模式吗?
出于某些原因,变量和函数可能会在 React 函数组件之外声明。例如,计时器 ID 和其他可以使用如下:
import React from "react";
const myFunc = () => { // no purpose
/*some codes*/
}
let myBool = false; // no purpose
let timerId = 0;
const MyComponent = () => {
const [name, setName] = useState("");
/* some codes */
useEffect(() => {
timerId = setTimeout(() => {
/* some codes */
}, 1000);
return () => clearTimeout(timerId);
}, []);
return (
<div>Hello world</div>
);
}
export default MyComponent;
对于可能改变的变量,比如在你的例子中,是的,它很可能被认为是一个问题,因为你不能指望任何使用具有一致效果的组件,因为它不是纯粹的,而是取决于外部变量的当前状态(而不是 React 状态)。
例如,如果您有一个 MyComponent
,后来您决定向您的站点添加另一个部分,该部分也使用了 MyComponent
,并且同时呈现了这两个部分,那么您现有的代码将导致问题,因为两个组件将共享相同的 timerId
变量 - 第一个渲染的组件将丢失其 timerId
。 (只有第二个要渲染的组件才能清除持久性外部 timerId
)
在这些情况下,组件内部使用的值属于该组件的给定实例,而不是整个应用程序,您应该使用状态(与 useState
) 而不是外部变量。
一般来说,使用外部标识符并不总是一个坏主意,但恰恰相反,对于不会改变并且对抽象有用的常量值,例如 URL、API 键, 分离非 React 函数,等等。以下类型的模式并不少见:
import { makeApiCall } from './makeApiCall';
export const SomeComponent = () => {
// ...more code here dealing with state
const handleClick = () => {
makeApiCall()
.then(handleSuccess)
.then(handleFail);
};
return (
<button onClick={handleClick}>click</button>
);
};
这样做不是犯罪。但在你这样做之前,想想你为什么要这样做。
如果你想像export { MyComponent, myFunc, timerId, myBool};
一样将这些变量连同组件一起暴露给外界,那么使用这种模式是有意义的。否则最好在功能组件本身内部声明 variable/function。
是的,这是一个反模式。 IMO 功能组件背后的整个想法是使组件纯净。使 React 函数组件变得纯净,使其更易于预测,您的输出仅由函数的输入决定。在函数范围之外使用变量会使函数不再纯粹。使用纯函数有几个好处。我强烈推荐使用纯功能组件。
是的,它被认为是反模式,您不能只在组件内定义这些变量,因为值将在重新呈现组件时重新初始化。 我们在 React 中有 ref 对象来实现这一点:
import React from "react";
const myFunc = () => { // no purpose
/*some codes*/
}
const MyComponent = () => {
const [name, setName] = useState("");
const myBool = useRef(false);
const timerId = useRef(0);
/* some codes */
useEffect(() => {
timerId.current = setTimeout(() => {
/* some codes */
}, 1000);
return () => clearTimeout(timerId.current);
}, []);
return (
<div>Hello world</div>
);
}
export default MyComponent;
myBool
和 timerId
不会在重新渲染时改变,您可以根据需要改变这些对象。您可以阅读更多 here.