Search code examples
javascriptreactjsreduxreact-hooks

Redux and ReactJS Hooks: UseEffect Returns an Empty State


I have this class component that returns state populated perfectly using Redux store:

class TopRatedComponent extends Component {
    componentDidMount() {
        this.props.fetchTopRatedMovies();
    }
    render() {

        const IMG_API_ROOT_LINK = 'https://image.tmdb.org/t/p/w500';
        const { topRatedMovies, loading, error } = this.props;
        return (
            <div>
                {loading && <div>LOADING...</div>}
                {error && <div>{error}</div>}
                <Container className="p-4" onScroll={this.onScroll}>

                    <div className="text-center">

                        {
                            topRatedMovies.results && topRatedMovies.results.map(topRated => (
                                <p>{topRated.title}</p>
                            ))
                        }
                    </div>

                </Container>

            </div>
        );
    }
}




const mapStateToProps = state => {
    const { topRatedMovies, loading, error } = state.topRatedMovies;
    return {
        topRatedMovies,
        loading,
        error
    };
};

export default connect(
    mapStateToProps,
    {
        fetchTopRatedMovies
    }
)(TopRatedComponent);

However, when I switch the above class component into a functional component below so I can use ReactJS hooks with my code, but the state is always empty.

const TopRatedComponent = () => {
      const [count, setCount] = useState(0);
      const [topRated, settopRated] = useState([]);

      useEffect(() => {
        settopRated(this.props.fetchTopRatedMovies)
     }, [this.props.fetchTopRatedMovies])
     
    
  const allState = useSelector((state) => state)
  console.log('CHOF: ' + JSON.stringify(allState));
  return (
    <div>
     WOOOOOOOW....
    </div>
  )
};

Solution

  • You haven't correctly transformed your class-based component into equivalent functional component.

    Following are the problems in your functional component:

    • In class component, you receive the fetchTopRatedMovies action creator as a prop and you dispatch it from the componentDidMount lifecycle method. In functional component, you are not dispatching it.

      To dispatch the action in functional components, use useDispatch() hook and use useEffect hook to dispatch this action after component has mounted.

      import React, { useEffect } from "react";
      import { useDispatch } from "react-redux";
      
      const TopRatedComponent = () => {
         ...
         const dispatch = useDispatch();
      
         useEffect(() => {
             dispatch(fetchTopRatedMovies());
         }, []);
      
         ...
      };
      
    • In class components, you access props object using this but in functional components, props object is passed as an argument. So, you can directly access it using the parameter name you use for the props object

      const TopRatedComponent = (props) => {
         console.log(props);
         // code
      };
      
    • Data that your component receives as props from the redux store using mapStateToProps function and connect higher order component, can be accessed using useSelector hook in functional components.

      import { useSelector } from "react-redux";
      
      const TopRatedComponent = () => {
          const { 
             topRatedMovies,
             loading,
             error
          } = useSelector(state => state.topRatedMovies);
      
          // code
      };
      

      Note: You can also use connect higher-order component and mapStateToProps to connect your functional component with the redux store.

    For details of how to use hooks with react-redux, see: react-redux - Hooks