简体   繁体   中英

React UseState hook causing infinite loop

I am using ReactJs to grab an RSS news feed every 5 seconds to convert it into a JSON string to render it on the webpage. I am using both useEffect and useState hook for this purpose as I am passing the JSON string in the useState hook variable, however. It kind of works but it produces an infinite loop. I have searched through the fixes provided in stack overflow but I couldn't find the exact problem. Here is my code snippet.'

import React, {useEffect, useState} from 'react';
import Carousel from 'react-bootstrap/Carousel';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import {getNews} from "../../actions/news";
import Parser from 'rss-parser';

const NewsCarousel = ({getNews, news: {news, loading} }) => {

    const [getFeed, setFeed] = useState({
        feed: ''
    });

    useEffect(() => {
        const interval = setInterval(() => {
            getNews();
        }, 5000);
        return () => clearInterval(interval);
    }, [getNews]);


    const { feed } = getFeed;
    const newsFeed = feed => setFeed({ ...getFeed, feed: feed });

    let parser = new Parser();
    parser.parseString(news, function(err, feed){
        if (!err) {
            newsFeed(feed);
        } else {
            console.log(err);
        }

    });

    console.log(feed);
    return (
        <div className="dark-overlay">
        </div>
    );
};


NewsCarousel.propTypes = {
    getNews: PropTypes.func.isRequired,
    news: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
    news: state.news
});

export default connect(mapStateToProps, {getNews}) (NewsCarousel);

Its when I console.log my feed variable that's when I see in the console the infinite logs. Below is my getNews Action

import axios from 'axios';
import { GET_NEWS, NEWS_FAIL } from "./types";

export const getNews = () => async dispatch => {
  try{
     const res = await axios.get('https://www.cbc.ca/cmlink/rss- 
     topstories');
     dispatch({
        type: GET_NEWS,
        payload: res.data
     })
} catch(err) {
    dispatch({
        type: NEWS_FAIL,
        payload: { msg: err}
    })
}
};

You need to parse your news only when there is a change in new props. Add another useEffect with news as a dependency so it will be called when the news changes and then update your state there.

import React, {useEffect, useState} from 'react';
import Carousel from 'react-bootstrap/Carousel';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import {getNews} from "../../actions/news";
import Parser from 'rss-parser';

const NewsCarousel = ({getNews, news: {news, loading} }) => {

    const [getFeed, setFeed] = useState({
        feed: ''
    });

    useEffect(() => {
        const interval = setInterval(() => {
            getNews();
        }, 5000);
        return () => clearInterval(interval);
    }, [getNews]);

    useEffect(() => {
      const newsFeed = feed => setFeed({ ...getFeed, feed: feed });

      const parser = new Parser();
      parser.parseString(news, function(err, feed){
        if (!err) {
            newsFeed(feed);
        } else {
            console.log(err);
        }
      });
    }, [news]);

    return (
        <div className="dark-overlay">
        </div>
    );
};


NewsCarousel.propTypes = {
    getNews: PropTypes.func.isRequired,
    news: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
    news: state.news
});

export default connect(mapStateToProps, {getNews}) (NewsCarousel);

You can make use of the Redux hook useDispatch to prevent the infinite loop here.

Instead of passing getNews to your NewsCarousel component via the connect higher-order component, you can make use of the useDispatch hook.

For example:

import { useDispatch } from "react-redux";
import { getNews } from "../../actions/news";

const NewsCarousel = props => {
    useEffect(() => {
        const dispatch = useDispatch();
        const interval = setInterval(() => {
            dispatch(getNews);
        }, 5000);
        return () => clearInterval(interval);
    }, [getNews]);

    // ...
}

Note that now getNews is not a prop but the function imported directly from the actions/news file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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