ComponentWillMount一直被重复调用
ComponentWillMount keeps being called repeately
我正在尝试调用后端api以获取页面加载时的用户配置文件:
给定以下动作:
export const GET_MY_PROFILE_START = 'GET_MY_PROFILE_START';
export const GET_MY_PROFILE_ERROR = 'GET_MY_PROFILE_ERROR';
export const GET_MY_PROFILE_SUCCESS = 'GET_MY_PROFILE_SUCCESS';
let a = 0;
export function getMyProfile() {
a = a+1;
window.console.log("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
window.console.log(a);
return dispatch => {
window.console.log("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
dispatch(getMyProfileStart());
$.ajax({
type: 'GET',
url: getMyProfileURL,
contentType: "application/json",
dataType: 'json',
}).done(function(res){
if (!res.values || res.values.count > 0) {
dispatch(getMyProfileSuccess(res.data))
} else {
dispatch(getMyProfileError())
}
}).fail(function(error) {
dispatch(getMyProfileError())
})
}
}
function getMyProfileStart() {
return {
type: GET_MY_PROFILE_START,
}
}
function getMyProfileSuccess(profile) {
return {
type: GET_MY_PROFILE_SUCCESS,
profile: profile,
}
}
function getMyProfileError() {
return {
type: GET_MY_PROFILE_ERROR,
}
}
及以下减速器:
import { SET_USER_PROFILE, CLEAR_USER_PROFILE, GET_MY_PROFILE_START, GET_MY_PROFILE_ERROR, GET_MY_PROFILE_SUCCESS } from '../serActions'
export default (state = {
loggedIn: false,
profiledLoading: false,
profile: {},
}, action) => {
switch (action.type) {
case SET_USER_PROFILE:
return {
loggedIn: true,
profiledLoading: false,
profile: {},
}
case CLEAR_USER_PROFILE:
return {
loggedIn: false,
profiledLoading: false,
profile: {},
}
case GET_MY_PROFILE_START:
return {
loggedIn: false,
profiledLoading: true,
profile: {},
}
case GET_MY_PROFILE_ERROR:
return {
loggedIn: true,
profiledLoaded: false,
profile: {},
}
case GET_MY_PROFILE_SUCCESS:
return {
loggedIn: true,
profiledLoading: false,
profile: action.profile,
}
default:
return state
}
}
和以下组件:
class AvatarButton extends Component {
componentWillMount() {
window.console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
this.props.dispatch(getMyProfile())
}
render() {
//const { profile, toggleMenu, showHideMenu } = this.props
const { user } = this.props
window.console.log(user);
return (
<a className="user-button nav-button avatar-button"
onClick={user.toggleMenu}
onBlur={this.hideMenu.bind(this)}
>
<i className="glyphicon glyphicon-user"/>
</a>
)
}
hideMenu() {
this.props.user.showHideMenu(false)
}
}
AvatarButton.propTypes = {
toggleMenu: PropTypes.func.isRequired,
showHideMenu: PropTypes.func.isRequired,
}
function select(state) {
return {
user: state.user,
}
}
// Wrap the component to inject dispatch and state into it
export default connect(select)(AvatarButton)
此组件用于:
class UserNavContainer extends Component {
constructor(props) {
super(props)
this.state = {
displayMenu: false,
}
}
render() {
const { dispatch, user, pathname } = this.props
if (!user.loggedIn)
return (
<LoginButton pathname={pathname}/>
)
return (
<div className="user-nav">
<AvatarButton
toggleMenu={this.toggleMenu.bind(this)}
showHideMenu={this.showHideMenu.bind(this)}
/>
<UserMenu
visible={this.state.displayMenu}
logoutHandler={this.logout.bind(this)}
hideMenu={this.showHideMenu.bind(this, false)}
/>
</div>
)
}
logout() {
window.location = "some url"
}
toggleMenu() {
this.showHideMenu(!this.state.displayMenu)
}
showHideMenu(show) {
this.setState({
displayMenu: show,
})
}
}
function select(state) {
return {
user: state.user,
}
}
// Wrap the component to inject dispatch and state into it
export default connect(select)(UserNavContainer)
最后是使用UserNavContainer的顶层组件:
class AppHandler extends Component {
componentWillMount() {
authUser(this.authSuccess.bind(this), this.authFail.bind(this))
}
authSuccess() {
this.props.dispatch(login())
}
authFail() {
this.props.dispatch(logout())
}
render() {
window.console.log("renderrenderrenderrenderrenderrenderrenderrenderrenderrender");
return (
<div className="app-container">
<div className="top-nav row">
<div className="col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1 col-xs-12">
<BackButton
pathname={this.props.location.pathname}
/>
<UserNavContainer
pathname={this.props.location.pathname}
/>
<div className="header">
<img src="https://www.wewherego.com/img/logo/logo_wherego.png"/>
<h1>{this.props.pageHeader}</h1>
</div>
</div>
</div>
<ReactCSSTransitionGroup
transitionName="example"
transitionEnterTimeout={1000}
transitionLeaveTimeout={1000}
>
{React.cloneElement(this.props.children, {
key: this.props.location.pathname,
})}
</ReactCSSTransitionGroup>
</div>
)
}
}
function select(state) {
return {
selectedCity: state.selectedCity,
pageHeader: state.pageHeader,
}
}
// Wrap the component to inject dispatch and state into it
export default connect(select)(AppHandler)
在AppHandler中,它调用了ComponentWillMount中的以下方法:
导出authUser(loginCb, logoutCb) {const data = readCookie('something')
if (!data) {
logoutCb()
} else {
loginCb()
}
return
}
导出函数signoutUser() {//清理一些东西}
当我打开页面时,我只能看到一行renderrenderrenderrenderrenderrenderrenderrenderrenderrenderrender
但是我看到日志一直在打印:
UserNavContainerUserNavContainerUserNavContainerUserNavContainerUserNavContainerUserNavContainer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
1057
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
1058
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
1059
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
显然,由于某种原因,componentWillMount方法一直被调用,并且getMyProfile()中的a现在变为1059(仍在计数)。
我不知道为什么会发生这种情况?
如果你在组件生命周期方法中调度动作,你应该在componentDidMount
而不是willMount中执行。看来你正在触发一个无限循环,阻止组件安装。
尝试将onClick函数调用包装为-
onClick={() => user.toggleMenu}
真正的问题是,在组件中,它们正在调度SET_USER_PROFILE事件,它将loggedIn变量更改为true,但随后应用程序调度GET_MY_PROFILE_START,它将loggedIn变量更改为false。这反过来触发新的循环,并将loggedIn移为true,因此循环继续进行。
正确的做法是在reducer中使用object而不是设置变量。赋值以更改变量的值。所以应该是:
export default (state = {
loggedIn: false,
profiledLoading: false,
profile: {},
}, action) => {
switch (action.type) {
case GET_MY_PROFILE_START:
return Object.assign({}, state, {
loggedIn: true,
profiledLoading: true,
})
case CLEAR_USER_PROFILE:
return Object.assign({}, state, {
loggedIn: false,
})
case GET_MY_PROFILE_ERROR:
return Object.assign({}, state, {
profiledLoaded: false,
profile: {},
})
case GET_MY_PROFILE_SUCCESS:
return Object.assign({}, state, {
profiledLoading: false,
profile: action.profile,
})
default:
return state
}
}
- 如何使jQuery插件函数可调用以供独立使用,而不在集合上操作
- D3在一个调用中绘制不同的SVG形状,没有可见性
- 如何从Java/scala调用js美化程序
- 如何调用这个匿名 JavaScript 函数
- 如何从模块链中调用函数.导出到节点中
- 我需要从php调用javascript或jquery
- Chrome开发工具(如何知道我在调用哪个javascript对象)
- 单击按钮后如何逐个调用分区,上一个分区将隐藏
- 另一个ajax调用中的Jquery ajax调用在for循环中没有按预期工作
- Twitter Bootstrap typeahead:使用“this”获取上下文/调用元素
- SetInterval一直在调用相同的函数
- 这个对象会一直重新调用函数吗
- Ajax 调用一直失败,没有错误
- knockoutjs调用一直在执行,怎么能只调用一次呢
- ComponentWillMount一直被重复调用
- 在ReactJS中,为什么componentDidMount在尝试包装jquery对话框时一直为我调用
- 如何在谷歌电子表格单元格中一直调用函数
- 试图在井字游戏中设置移动,但当我调用该函数时,我一直没有定义
- 在JS中调用二维数组时,一直未定义
- 为什么获胜't这个Javascript方法一直在调用自己