我有一个用例,我需要卸载我的反应组件。但在某些情况下,特定的反应组分是由不同的功能卸载的。 因此,我需要在卸载之前检查组件是否已安装。
答案 0 :(得分:75)
由于isMounted()
正式弃用,您可以在组件中执行此操作:
componentDidMount() {
this._ismounted = true;
}
componentWillUnmount() {
this._ismounted = false;
}
ReactJS文档中详细介绍了维护自己的state
变量的模式:https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html
答案 1 :(得分:19)
我认为Shubham的回答是针对那些需要转换代码以停止使用isMounted
反模式的人的反应建议。
这不一定是坏事,但值得列出这个问题的真正解决方案。
The article linked by Shubham提供了2条避免这种反模式的建议。您需要的那个取决于卸载组件时调用setState的原因。
如果您在组件中使用Flux存储,则必须取消订阅componentWillUnmount
class MyComponent extends React.Component {
componentDidMount() {
mydatastore.subscribe(this);
}
render() {
...
}
componentWillUnmount() {
mydatastore.unsubscribe(this);
}
}
如果您使用ES6承诺,您可能需要包装您的承诺以使其可取消。
const cancelablePromise = makeCancelable(
new Promise(r => component.setState({...}}))
);
cancelablePromise
.promise
.then(() => console.log('resolved'))
.catch((reason) => console.log('isCanceled', reason.isCanceled));
cancelablePromise.cancel(); // Cancel the promise
在链接文章中详细了解makeCancelable
。
总之,不要尝试通过设置变量并检查组件是否已挂载来修补此问题,转到问题的根源。如果您能提出任何常见案例,请对其进行评论。
答案 2 :(得分:7)
另一个解决方案是使用Refs。如果您使用的是React 16.3+,请在渲染功能中引用您的顶级项目。
然后只需检查ref.current是否为空。
示例:
class MyClass extends React.Component {
constructor(props) {
super(props);
this.elementRef = React.createRef();
}
checkIfMounted() {
return this.elementRef.current != null;
}
render() {
return (
<div ref={this.elementRef} />
);
}
}
答案 3 :(得分:4)
我来到这里是因为我正在寻找一种方法来阻止polling
API。
react docs确实涵盖了websocket
案例,但不包括民意调查案例。
我的工作方式
// React component
React.createClass({
poll () {
if (this.unmounted) {
return
}
// otherwise, call the api
}
componentWillUnmount () {
this.unmounted = true
}
})
它有效。希望它有所帮助
如果你们知道任何失败的测试用例,请告诉我这个=]
答案 4 :(得分:2)
我们建议您不要使用useState
挂钩来跟踪组件是否已安装,因为每当更新状态时,react都会重新渲染整个组件组件,它也会触发useEffect或其他挂钩的执行。
function MyComponent(props: Props) {
const isMounted = useRef(false)
useEffect(() => {
isMounted.current = true;
return () => (isMounted.current = false)
}, []);
return (...);
}
export default MyComponent;
答案 5 :(得分:1)
相同的想法,但还有其他实现方式
/**
* component with async action within
*
* @public
*/
class MyComponent extends Component {
constructor ( ...args ) {
// do not forget about super =)
super(...args);
// NOTE correct store "setState"
let originSetState = this.setState.bind(this);
// NOTE override
this.setState = ( ...args ) => !this.isUnmounted&&originSetState(...args);
}
/**
* no necessary setup flag on component mount
* @public
*/
componentWillUnmount() {
// NOTE setup flag
this.isUnmounted = true;
}
/**
*
* @public
*/
myCustomAsyncAction () {
// ... code
this.setState({any: 'data'}); // do not care about component status
// ... code
}
render () { /* ... */ }
}
答案 6 :(得分:1)
如果您使用的是钩子:
function MyComponent(props: Props) {
const [isMounted, setIsMounted] = useState<boolean>(false);
useEffect(() => {
setIsMounted(true);
}, []);
useEffect(() => {
return () => {
setIsMounted(false);
}
}, []);
return (...);
}
export default MyComponent;
答案 7 :(得分:0)
我发现组件将被卸载,生成填充此var
if(!this._calledComponentWillUnmount)this.setState({vars});
答案 8 :(得分:0)
使用@DerekSoike答案,但是在我的情况下,使用useState
来控制挂载状态不起作用,因为该状态在不需要时可以恢复
对我有用的是使用单个变量
myFunct
是在setTimeout
中调用的,我的猜测是,当同一组件在另一个页面中初始化该钩子时,它会恢复状态,从而导致内存泄漏再次出现
所以这对我不起作用
const [isMounted, setIsMounted] = useState(false)
useEffect(() => {
setIsMounted(true)
return () => setIsMounted(false)
}, [])
const myFunct = () => {
console.log(isMounted) // not always false
if (!isMounted) return
// change a state
}
这确实对我有用
let stillMounted = { value: false }
useEffect(() => {
stillMounted.value = true
return () => (stillMounted.value = false)
}, [])
const myFunct = () => {
if (!stillMounted.value) return
// change a state
}
答案 9 :(得分:-1)
您可以使用:
myComponent.updater.isMounted(myComponent)
“ myComponent”是您的react组件的实例。 如果已安装组件,则返回“ true”,否则将返回“ false”。