在componentWillReceiveProps中调度时的无限循环

时间:2016-03-23 22:18:24

标签: reactjs react-router redux react-redux react-router-redux

我有一个由react-router(path =“profile /:username”)加载的Profile组件,组件本身如下所示:

...
import { fetchUser } from '../actions/user';

class Profile extends Component {
  constructor(props) {
    super(props);
  }
  componentDidMount() {
    const { username } = this.props;
    this.fetchUser(username);
  }
  componentWillReceiveProps(nextProps) {
    const { username } = nextProps.params;
    this.fetchUser(username);
  }
  fetchUser(username) {
    const { dispatch } = this.props;
    dispatch(fetchUser(username));
  }
  render() {...}
}

export default connect((state, ownProps) => {
  return {
    username: ownProps.params.username,
    isAuthenticated: state.auth.isAuthenticated
  };
})(Profile);

fetchUser动作看起来像这样(redux-api-middleware):

function fetchUser(id) {
  let token = localStorage.getItem('jwt');
  return {
    [CALL_API]: {
      endpoint: `http://localhost:3000/api/users/${id}`,
      method: 'GET',
      headers: { 'x-access-token': token },
      types: [FETCH_USER_REQUEST, FETCH_USER_SUCCESS, FETCH_USER_FAILURE]
    }
  }
}

我添加componentWillReceiveProps函数的原因是当URL更改为另一个时生效:用户名并加载用户个人资料信息。乍一看,一切似乎都有效,但后来我注意到调试时,在无限循环中调用了componentWillReceiveProps函数,我不知道为什么。如果我删除componentWillReceiveProps,那么配置文件不会使用新用户名更新,但我没有循环问题。有什么想法吗?

3 个答案:

答案 0 :(得分:18)

尝试添加条件来比较道具。如果您的组件需要它。

componentWillRecieveProps(nextProps){
 if(nextProps.value !== this.props.value)
  dispatch(action()) //do dispatch here 
}

答案 1 :(得分:9)

您的componentWillReceiveProps处于无限循环中,因为调用fetchUser将调度将更新道具的操作。

添加比较以在分派操作之前检查特定道具是否更改。 编辑:

React 16.3 + componentWillReceiveProps将慢慢弃用

  

推荐使用componentDidUpdate代替componentWillReceiveProps

componentDidUpdate(prevProps) {
  if (this.props.params.username !== prevProps.params.username) {
    dispatch(fetchUser(username));
  }
}

请参阅https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#fetching-external-data-when-props-change

答案 2 :(得分:6)

如果你有一些路径参数的路由,比如profile /:username, 您只需比较 props.location.pathname

即可
componentWillReceiveProps(nextProps){    
    if(nextProps.location.pathname !== this.props.location.pathname){
          dispatch()
        }
 }