我们如何在参数中的componentDidMount
钩中设置setState?
我的问题是React的警告通知:
Warning: Can't call setState (or forceUpdate) on an unmounted
component. This is a no-op, but it indicates a memory leak in your
application. To fix, cancel all subscriptions and asynchronous tasks in the
componentWillUnmount method.
in DiscoverPage (created by Route)
在我的DiscoverPage
组件中:
import React, { Component } from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
import TvShows from './TvShows';
import Movies from './Movies';
import MovieDetail from "../MoviePage/MovieDetail";
import TvDetail from "../TvShowPage/TvDetail";
class DiscoverPage extends Component {
constructor(props) {
super(props);
this.state = {
data: {}
}
}
getDataItem = (data) => {
this.setState({ data: data });
};
render() {
return (
<Switch>
<Route exact path="/discover/movie" render={props => <Movies data={this.getDataItem} {...props} />} />
<Route path="/discover/tv" render={props => <TvShows data={this.getDataItem} {...props} />} />
<Route path="/movie/:movie" render={props => <MovieDetail data={this.state.data} {...props} />} />
<Route path="/tv/:tv" render={props => <TvDetail data={this.state.data} {...props} />} />
<Redirect to="/discover/movie" />
</Switch>
);
}
}
export default DiscoverPage;
在子组件中(本例为Movies
组件):
import React, { Component } from 'react';
import requestApi from '../api';
import MovieList from "../MoviePage/MovieList";
class Movies extends Component {
constructor(props) {
super(props);
this.state = {
data: {
page: 1,
results: []
}
}
}
componentDidMount() {
requestApi.fetchData('discover', 'movie').then(response => {
this.setState({ data: response.data, isLoading: false });
});
}
getMoviebyId = (id) => {
requestApi.fetchDataById('movie', id).then(response => {
this.props.data(response.data);
});
};
nextPage = (e) => {
const page = this.state.data.page + 1;
requestApi.fetchDataPaginate('discover', 'movie', page).then(response => {
this.setState({data: response.data});
});
};
prevPaginate = (e) => {
const page = this.state.data.page - 1;
requestApi.fetchDataPaginate('discover', 'movie', page).then(response => {
this.setState({ data: response.data });
});
};
render() {
return (
<div className="container">
<div className="ss_media">
<h2 className="title">Discover New Movies & TV Shows</h2>
<MovieList
movie={this.getMoviebyId}
routeProps={this.props}
prevPaginate={this.prevPaginate}
nextPaginate={this.nextPage}
moviesList={this.state.data} />
</div>
</div>
);
}
}
export default Movies;
我该如何解决?谢谢。
答案 0 :(得分:2)
当路由更改时,然后调用getDataItem方法时,将卸载DiscoverPage组件。这就是为什么react抛出错误。
我建议使用react-router组件方法,而不是渲染并将数据移动到可以由任何组件访问的存储中。请参阅react-router render methods
示例:
<Route path="/user/:username" component={User}/>
答案 1 :(得分:1)
需要做一些更改,您使用的逻辑效率不高
从您的问题中了解到我的想法会很好
import React, { Component } from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
import TvShows from './TvShows';
import Movies from './Movies';
import MovieDetail from '../MoviePage/MovieDetail';
import TvDetail from '../TvShowPage/TvDetail';
class DiscoverPage extends Component {
constructor(props) {
super(props);
this.state = {
data: {}
};
}
getALLDATA() {
//update your state after your request
request().then(res => {
this.setState({
data: res.data
});
});
}
componentDidMount() {
this.getALLDATA();
}
getDataItem = () => {
return this.state.data;
};
render() {
return (
<Switch>
<Route exact path="/discover/movie" render={props => <Movies data={this.getDataItem} {...props} />} />
<Route path="/discover/tv" render={props => <TvShows data={this.getDataItem} {...props} />} />
<Route path="/movie/:movie" render={props => <MovieDetail data={this.state.data} {...props} />} />
<Route path="/tv/:tv" render={props => <TvDetail data={this.state.data} {...props} />} />
<Redirect to="/discover/movie" />
</Switch>
);
}
}
export default DiscoverPage;
答案 2 :(得分:1)
您收到的警告是告诉您无法在未安装的组件(即当前未渲染的组件)上调用setState
。您的其他组件之一(Movies
,TvShows
等)很可能正在调用您作为data
道具传递的方法。呈现这些组件之一时,DiscoveryPage
组件未呈现,因此通过getDataItem
道具调用data
将导致DiscoveryPage
的{{1}}方法未呈现时调用。为了解决这个问题(假设您要做的是将数据从一个组件传递到另一个组件),我建议也许使用setState
来存储一个共享变量(或者,如@Anu所建议的那样,使用其他某种存储方式)。
我不明白您对“在参数中”的含义,但是,回答您的问题,您可以使用任何localStorage
方法调用setState
(即使在component...
中调用毫无意义,因为只有在即将卸载组件时才调用此方法。
编辑:
查看componentWillUnmount
组件。在Movie
方法中将localStorage
用作我们的商店,而不是:
getMovieById
您可能会遇到类似的事情:
getMoviebyId = (id) => {
requestApi.fetchDataById('movie', id).then(response => {
//this next sentence will call DiscoveryPage's setState
//DiscoveryPage is not mounted, so a warning will be raised
this.props.data(response.data);
});
};
,然后在其他组件或方法中,按如下方式访问它:
getMoviebyId = (id) => {
requestApi.fetchDataById('movie', id).then(response => {
//any component can access this store
localStorage.setItem("data", response.data);
});
};
您的代码有点混乱。我在理解您使用localStorage.getItem("data");
的{{1}}的位置时遇到了一些麻烦,这是您在调用DiscoveryPage
方法时要设置的位置。但是无论如何,希望这会有所帮助。
还有一个补充说明:使用data
时,这是一种很好的管理方式,也就是说,使用完data
值后,请调用localStorage
。例如,最好使用某些localStorage.removeItem("data")
方法。
答案 3 :(得分:0)
我认为您缺少从react-router-dom
import { Switch, Route, Redirect, BrowserRouter } from 'react-router-dom'; // Add BrowserRouter
class DiscoverPage extends Component {
...
render() {
return (
<BrowserRouter> // Add this
<Switch>
<Route exact path="/discover/movie" render={props => <Movies data={this.getDataItem} {...props} />} />
<Route path="/discover/tv" render={props => <TvShows data={this.getDataItem} {...props} />} />
<Route path="/movie/:movie" render={props => <MovieDetail data={this.state.data} {...props} />} />
<Route path="/tv/:tv" render={props => <TvDetail data={this.state.data} {...props} />} />
<Redirect to="/discover/movie" />
</Switch>
</BrowserRouter>
);
}
}
答案 4 :(得分:0)
我们可以在 componentDidMount 中设置状态,例如:
eval
但改为使用 componentDidUpdate :
(setq-default compile-command 'my-compile-command-fun)