简体   繁体   English

useEffect 导致无限循环

[英]useEffect is causing an infinite Loop

I am getting an infinite loop and it is constantly fetching information from the API.我得到一个无限循环,它不断从 API 获取信息。

The issue can be solved if I wrap fetchTheMovie() inside an if statement but I do not understand the reason, any ideas or any better solution?如果我将 fetchTheMovie() 包装在 if 语句中,问题可以解决,但我不明白原因、任何想法或任何更好的解决方案?

if (!movie.Title) {
  fetchTheMovie(id);
}

The endpoint is /movie/id端点是 /movie/id

Movie Component:电影组件:

const SingleMovie = (props) => {
  const { id } = useParams();
  const {movie} = props;

  useEffect(() => {
    const {fetchTheMovie} = props;
    fetchTheMovie(id);
  }, []);
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(WithSpinner(SingleMovie));

WithSpinner Component : WithSpinner 组件

const WithSpinner = (WrappedComponent) => {
  const Spinner = ({ isLoading, ...otherProps }) => {
    return isLoading ? (
      <SpinnerOverlay>
        <SpinnerContainer />
      </SpinnerOverlay>
    ) : (
      <WrappedComponent {...otherProps} />
    );
  };
  return Spinner;
};

Page that the component is used使用该组件的页面

const Page = ({ loading }) => {
  const { id } = useParams();
  return (
    <div>
      <SingleMovieComp isLoading={loading} />
    </div>
  );
};

Action:行动:

export function fetchMovieStart() {
  return {
    type: SingleMovieActionTypes.FETCH_MOVIE_START,
  };
}

export function fetchMovieSuccess(movie) {
  return {
    type: SingleMovieActionTypes.FETCH_MOVIE_SUCCESS,
    payload: movie,
  };
}

export function fetchMovieError(error) {
  return {
    type: SingleMovieActionTypes.FETCH_MOVIE_ERROR,
    payload: error,
  };
}

export const fetchMovieAsync = (movieId) => {
  return (dispatch) => {
    dispatch(fetchMovieStart());
    fetch(`URL`)
      .then((response) => response.json())
      .then((movie) => dispatch(fetchMovieSuccess(movie)))
      .catch((error) => dispatch(fetchMovieError(error.message)));
  };
};

Reducer:减速器:

const INITIAL_STATE = {
  loading: false,
  movie: {},
};

const singleMovieReducer = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case SingleMovieActionTypes.FETCH_MOVIE_START: {
      return {
        ...state,
        movie: {},
        loading: true,
      };
    }
    case SingleMovieActionTypes.FETCH_MOVIE_SUCCESS: {
      return {
        ...state,
        movie: action.payload,
        loading: false,
      };
    }
    case SingleMovieActionTypes.FETCH_MOVIE_ERROR: {
      return {
        ...state,
        loading: false,
      };
    }
    default:
      return state;
  }
};

You can try the following:您可以尝试以下方法:

const ComponentWithSpinner = WithSpinner(SingleMovie);
//create single movie container
const SingleMovieContainer = (props) => {
  const { id } = useParams();
  const { fetchTheMovie } = props;
  //remove the useEffect from SingleMovie
  useEffect(() => {
    fetchTheMovie(id);
    //you need to add these dependencies
  }, [fetchTheMovie, id]);
  //Here you could try to use useSelector to get the movie
  //  and pass to SingleMovie but I think you already do
  //  that somewhere else
  //return component with spinner so SingleMovieContainer
  // will not unmount when you load movie
  return <ComponentWithSpinner {...props} />;
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(SingleMovieContainer);

Problem is that SingleMovie is unmounted when you load a movie and gets mounted when loading is false, that causes loading to be set true (fetchMovie is dispatched) so it is unmounted again.问题是 SingleMovie 在您加载电影时被卸载,并且在加载为假时被安装,这导致加载设置为 true(已调度 fetchMovie),因此它再次被卸载。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM