web-dev-qa-db-ja.com

componentWillReceivePropsでディスパッチするときの無限ループ

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が別の:usernameに変更されたときに反応し、そのユーザーのプロファイル情報をロードするためです。一見、すべてが機能しているように見えますが、デバッグ中に、componentWillReceiveProps関数が無限ループで呼び出されていることがわかりました。理由はわかりません。 componentWillReceivePropsを削除すると、プロファイルは新しいユーザー名で更新されませんが、ループの問題は発生しません。何か案は?

13
hazmah0

componentWillReceivePropsを呼び出すと、Propsを更新するアクションが送出されるため、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 を参照してください

10
Kenneth Truong

小道具を比較する条件を追加してみてください。コンポーネントで必要な場合。

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

Profile /:usernameのようないくつかのパスパラメータを使用してルートを反応させる場合、単純にprops.location.pathnameを比較できます。

componentWillReceiveProps(nextProps){    
    if(nextProps.location.pathname !== this.props.location.pathname){
          dispatch()
        }
 }  
6
RPaul