Search code examples
reactjsredux

React Hook useEffect has a missing dependency: 'props'. Either include it or remove the dependency array. props in useEffect have no data


i used axios to call api methods for data access in react hooks components .i used react redux for state management. i call the fetchall method from useEffect to get all courses. but the response array is empty and show above error.there is problem with state or props like that .or the course reducer does not fetch data .here is code of api.js in action.

import axios from "axios";

const baseUrl = "http://localhost:44306/api/"



export default {

    course(url = baseUrl + 'courses/') {
        return {
            fetchAll: () => axios.get(url),
            fetchById: id => axios.get(url + id),
            create: newRecord => axios.post(url, newRecord),
            update: (id, updateRecord) => axios.put(url + id, updateRecord),
            delete: id => axios.delete(url + id)
        }
    }
}

the courses components have 2 grids first Grid has been commented out to focus on problem. the second grid have table which should show courses in table. the backend table has many rows which has been tested with postman and from database. the courses.js is as follows.

import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import * as actions from "../actions/course";
import { Grid, Paper, TableContainer, Table, TableHead, TableRow, TableCell, TableBody, withStyles, ButtonGroup, Button } from "@material-ui/core";
import CourseForm from "./CourseForm";
import EditIcon from "@material-ui/icons/Edit";
import DeleteIcon from "@material-ui/icons/Delete";
import { useToasts } from "react-toast-notifications";



const styles = theme => ({
    root: {
        "& .MuiTableCell-head": {
            fontSize: "1.25rem"
        }
    },
    paper: {
        margin: theme.spacing(2),
        padding: theme.spacing(2)
    }
})





const Courses = ({ classes, ...props }) => {
    const [currentId, setCurrentId] =useState(0)
    useEffect(() => {
        props.fetchAllCourses()    // here is error props is empty

    }, [])//componentDidMount

    //toast msg.
    const { addToast } = useToasts()

    const onDelete = id => {
        if (window.confirm('Are you sure to delete this record?'))
            props.deleteCourse(id,()=>addToast("Deleted successfully", { appearance: 'info' }))
    }





    return (
        <Paper className={classes.paper} elevation={3}>
            <Grid container>
                <Grid item xs={6}>

                    {/* <CourseForm {...({ currentId, setCurrentId })} /> */}
                </Grid>
                <Grid item xs={6}>
                    <TableContainer>
                        { <Table>
                            <TableHead className={classes.root}>
                                <TableRow>
                                    <TableCell>Title</TableCell>
                                    <TableCell>Details</TableCell>
                                    <TableCell>Category</TableCell>
                                    <TableCell></TableCell>
                                </TableRow>
                            </TableHead>
                            <TableBody>
                                {
                                    props.courseList.map((record, index) => {
                                        return (<TableRow key={index} hover>
                                            <TableCell>{record.Title}</TableCell>
                                            <TableCell>{record.Details}</TableCell>
                                            <TableCell>{record.Category}</TableCell>
                                            <TableCell>
                                                <ButtonGroup variant="text">
                                                    <Button><EditIcon color="primary"
                                                        onClick={() => { setCurrentId(record.id) }} /></Button>
                                                    <Button><DeleteIcon color="secondary"
                                                        onClick={() => onDelete(record.id)} /></Button>
                                                </ButtonGroup>
                                            </TableCell>
                                        </TableRow>)
                                    })
                                }
                            </TableBody>
                        </Table> }
                    </TableContainer>

                </Grid>
            </Grid>
        </Paper>
    );
}

const mapStateToProps = state => ({
    courseList: state.course.list
})

const mapActionToProps = {
    fetchAllCourses: actions.fetchAll,
    deleteCourse: actions.Delete
}

export default connect(mapStateToProps, mapActionToProps)(withStyles(styles)(Courses));

the course.js in actions is as follows:

import api from "./api";

export const ACTION_TYPES = {
    CREATE: 'CREATE',
    UPDATE: 'UPDATE',
    DELETE: 'DELETE',
    FETCH_ALL: 'FETCH_ALL'
}

const formateData = data => ({
    ...data,

})

export const fetchAll = () => dispatch => {
    api.course().fetchAll()
        .then(response => {
            console.log(response)
            dispatch({
                type: ACTION_TYPES.FETCH_ALL,
                payload: response.data
            })
        })
        .catch(err => console.log(err))
}

export const create = (data, onSuccess) => dispatch => {
    data = formateData(data)
    api.course().create(data)
        .then(res => {
            dispatch({
                type: ACTION_TYPES.CREATE,
                payload: res.data
            })
            onSuccess()
        })
        .catch(err => console.log(err))
}

export const update = (id, data, onSuccess) => dispatch => {
    data = formateData(data)
    api.course().update(id, data)
        .then(res => {
            dispatch({
                type: ACTION_TYPES.UPDATE,
                payload: { id, ...data }
            })
            onSuccess()
        })
        .catch(err => console.log(err))
}

export const Delete = (id, onSuccess) => dispatch => {
    api.course().delete(id)
        .then(res => {
            dispatch({
                type: ACTION_TYPES.DELETE,
                payload: id
            })
            onSuccess()
        })
        .catch(err => console.log(err))
}

the course.js in reducer is as :

import { ACTION_TYPES } from "../actions/course";
const initialState = {
    list: []
}


export const course = (state = initialState, action) => {

    switch (action.ACTION_TYPES) {
        case ACTION_TYPES.FETCH_ALL:
            return {
                ...state,
                list: [...action.payload]
            }

        case ACTION_TYPES.CREATE:
            return {
                ...state,
                list: [...state.list, action.payload]
            }

        case ACTION_TYPES.UPDATE:
            return {
                ...state,
                list: state.list.map(x => x.id == action.payload.id ? action.payload : x)
            }

        case ACTION_TYPES.DELETE:
            return {
                ...state,
                list: state.list.filter(x => x.id != action.payload)
            }

        default:
            return state
    }
}

why the useeffect does not access the props. how to access props in useEffect i will be very thankful for kind help. the index.js in reducer is as:

import { combineReducers } from "redux";
import { course } from "./course";

export const reducers = combineReducers({
    course
})

thanks in advance.


Solution

  • Seems like you need to pass the needed dependency to useEffect as mentioned in the error message.

    useEffect(() => {
      props.fetchAllCourses()
    }, [props.fetchAllCourses]);
    

    UPDATE: After reading the full error message in the comments, seems like you need to destructure the props:

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