Couple days ago I posted a question where I had a problem with params to fetch an ID that I needed.
Yesterday I was working with Redux to fetch some data dynamically and I stepped on a problem that the page renders but nos data is displayed (the Redux extension return an empty array) and got an warning on the console saying this
React Hook useEffect has missing dependencies: 'dis patch' and 'id'. Either include them or remove the dependency arr ay react-hooks/exhaustive-deps
This is my code:
ProductScreen.js
import React, { useEffect } from 'react';
import { Link, useParams } from "react-router-dom";
import { useDispatch, useSelector } from 'react-redux';
// Fontawesome
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAngleLeft } from "@fortawesome/free-solid-svg-icons";
import { detailsProduct } from '../actions/productActions';
function ProductScreen(props) {
const {id} = useParams();
//console.log(id)
//const product = data.products.find(x=> x._id === id);
const productDetails = useSelector(state => state.productDetails);
const {product, loading, error} = productDetails;
const dispatch = useDispatch();
useEffect(() => {
dispatch(detailsProduct(id));
return () => {
//
};
}, [])
return (
<div>
<div className="back-to-main">
<Link to="/"> <FontAwesomeIcon icon={faAngleLeft} /> Back to main page</Link>
</div>
{loading? <div>Loading...</div>:
error? <div>{error}</div>:
(
<div className="details">
<div className="details-image">
<img src={product.image} alt="product"></img>
</div>
<div className="details-info">
<ul>
<li>
<h4>{product.name}</h4>
</li>
<li>
{product.rating} Leafs ({product.numberReviews} Reviews)
</li>
<li>
Price: <b>${product.price}</b>
</li>
<li>
Description:
<div>
{product.description}
</div>
</li>
</ul>
</div>
<div className="details-action">
<ul>
<li>
Price: {product.price}
</li>
<li>
Status: {product.status}
</li>
<li>
Qty: <select>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
<option>10</option>
</select>
</li>
<li>
<button className="button primary">Add to cart</button>
</li>
</ul>
</div>
</div>
)
}
</div>
);
}
export default ProductScreen;
server.js
import express from 'express';
import data from './data';
const app = express();
app.get("/api/products", (req, res) => {
res.send(data.products);
});
app.get("/api/products/:id", (req, res) => {
const productId = req.params.id;
const product = data.products.find(x=>x._id === productId);
if(product)
res.send();
else
res.status(404).send({msg: "Product Not Found."});
});
app.listen(5000, () => {console.log("Server started at http://localhost:5000")});
productActions.js
import axios from "axios";
import { PRODUCT_DETAILS_FAIL, PRODUCT_DETAILS_REQUEST, PRODUCT_DETAILS_SUCCESS,
PRODUCT_LIST_FAIL, PRODUCT_LIST_REQUEST, PRODUCT_LIST_SUCCESS
} from "../constants/productConstants"
const listProducts = () => async (dispatch) => {
try {
dispatch({type: PRODUCT_LIST_REQUEST});
const { data } = await axios.get("/api/products");
dispatch({ type: PRODUCT_LIST_SUCCESS, payload: data });
} catch (error) {
dispatch({ type: PRODUCT_LIST_FAIL, payload: error.message });
}
}
const detailsProduct = (productId) => async (dispatch) => {
try {
dispatch({ type: PRODUCT_DETAILS_REQUEST, payload: productId });
const { data } = await axios.get("/api/products/" + productId);
dispatch({ type: PRODUCT_DETAILS_SUCCESS, payload: data });
}catch (error){
dispatch({ type: PRODUCT_DETAILS_FAIL, payload: error.message })
}
}
export { listProducts, detailsProduct }
productReducer.js
import { PRODUCT_DETAILS_FAIL, PRODUCT_DETAILS_REQUEST, PRODUCT_DETAILS_SUCCESS,
PRODUCT_LIST_FAIL, PRODUCT_LIST_REQUEST, PRODUCT_LIST_SUCCESS
} from "../constants/productConstants";
function productListReducer(state= {products:[]}, action) {
switch (action.type) {
case PRODUCT_LIST_REQUEST:
return {loading: true};
case PRODUCT_LIST_SUCCESS:
return {loading: false, products: action.payload};
case PRODUCT_LIST_FAIL:
return {loading: false, error: action.payload}
default:
return state;
}
}
function productDetailsReducer(state= {product: {}}, action) {
switch (action.type) {
case PRODUCT_DETAILS_REQUEST:
return {loading: true};
case PRODUCT_DETAILS_SUCCESS:
return {loading: false, product: action.payload};
case PRODUCT_DETAILS_FAIL:
return {loading: false, error: action.payload}
default:
return state;
}
}
export { productListReducer, productDetailsReducer }
store.js
import { createStore, combineReducers, compose, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { productDetailsReducer, productListReducer } from './reducer/productReducers';
const initialState = {};
const reducer = combineReducers({
productList: productListReducer,
productDetails: productDetailsReducer,
})
const composeEnhancers = (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose;
const store = createStore(reducer, initialState, composeEnhancers(applyMiddleware(thunk)));
export default store;
productConstants.js
export const PRODUCT_LIST_REQUEST = 'PRODUCT_LIST_REQUEST';
export const PRODUCT_LIST_SUCCESS = 'PRODUCT_LIST_SUCCESS';
export const PRODUCT_LIST_FAIL = 'PRODUCT_LIST_FAIL';
export const PRODUCT_DETAILS_REQUEST = 'PRODUCT_DETAILS_REQUEST';
export const PRODUCT_DETAILS_SUCCESS = 'PRODUCT_DETAILS_SUCCESS';
export const PRODUCT_DETAILS_FAIL = 'PRODUCT_DETAILS_FAIL';
I tried to insert the ID parameter on the useEffect function on ProductScreen.js but the dispatch() still shows as an alert/warning.
Where I'm going wrong?
PS: Is a e-commerce app