-1

So I've been following a MERN stack course but somehow the react-router-dom version he is using is outdated. I keep having this error:

Uncaught TypeError: Cannot read properties of undefined (reading 'params')

I've tried changing the code to align it with the updated version such as using useParams(); but I think I have implemented the code wrong.

Here is the original code for the ProductScreen.js component currently using v6.3 of react-router-dom:

const ProductScreen = ({match}) => {
 

  const dispatch = useDispatch();
  
  const productDetails = useSelector(state => state.productDetails);
  const {loading, error, product} = productDetails;

  useEffect (() => {
    dispatch(listProductDetails(match.params.id));
  },[dispatch, match]);
      return(//code here)

Here is the productActions.js file:

export 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.response && error.response.data.message ? error.response.data.message : error.message,
        })
    }
}
export const listProductDetails = (id) => async (dispatch) =>{
    try{
        dispatch({ type: PRODUCT_DETAILS_REQUEST});

        const {data} = await axios.get(`api/products/${id}`);
        
        dispatch({
            type: PRODUCT_DETAILS_SUCCESS,
            payload: data,
            
        })
        
    }catch(error){
        dispatch({
            type: PRODUCT_DETAILS_FAIL,
            payload: error.response && error.response.data.message ? error.response.data.message : error.message,
        })
    }
}

Here is my Product.js file:

const Product = ({ product }) => {
  return (
    <div>
        <Card className='my-3 p-3 rounded'>
            <Link to={`/product/${product._id}`}>
                <Card.Img src={product.image} variant='top' />
            </Link>
            <Card.Body>
                <Link to={`/product/${product._id}`}>
                    <Card.Title as='div'><p>{product.name}</p></Card.Title>
                </Link>
                <Card.Text as='div'>
                    <Rating 
                    value={product.rating} 
                    text={`${product.numReviews} reviews`} />
                </Card.Text >
                <Card.Text as='h3'>
                    ₱{product.price}
                </Card.Text>
            </Card.Body>
        </Card>
    </div>
  )
}

Here is my productReducers.js:

export const productListReducer = (state = { products: []}, action) => {
    switch(action.type){
        case PRODUCT_LIST_REQUEST:
            return{loading: true, products: []}
        case PRODUCT_LIST_SUCCESS:
            return {loading: false, products: action.payload}
        case PRODUCT_LIST_FAIL:
            return {loading: false, error: action.payload}
        default:
            return state
    }
}

export const productDetailsReducer = (state = { product: {reviews: []}}, action) => {
    switch(action.type){
        case PRODUCT_DETAILS_REQUEST:
            return{loading: true, ...state}
        case PRODUCT_DETAILS_SUCCESS:
            return {loading: false, product: action.payload}
        case PRODUCT_DETAILS_FAIL:
            return {loading: false, error: action.payload}
        default:
            return state
    }
}

Thanks a lot!

  • *somehow the react-router-dom version he is using is outdated* - libraries changes very often. A course that was published more than two years ago will usually be outdated. You can always use an older version of the library to match the course. – Konrad Aug 28 '22 at 12:51
  • Also, you didn't give us enough code to find the issue. You didn't specify what version of the library was in the original course and what version you have now.u – Konrad Aug 28 '22 at 12:52
  • Sorry for the issues with my query, I've updated the question. Thanks for the advice! – Jeheu Dela Cruz Aug 28 '22 at 13:22

2 Answers2

0

The problem is most likely here:

const ProductScreen = ({match}) => {

match has been replaced with useMatch

Try doing this:

const ProductScreen = () => {
  const match = useMatch();
Konrad
  • 21,590
  • 4
  • 28
  • 64
  • I tried doing this fix but I'm afraid that it returned this error: Uncaught TypeError: Cannot read properties of undefined (reading 'path') – Jeheu Dela Cruz Aug 28 '22 at 13:50
0

So after few hours of trial and error, I've managed to solve this:

in ProductScreen.js:

const ProductScreen = () => {
 

  const dispatch = useDispatch();
  const {id} = useParams();
  
  const productDetails = useSelector(state => state.productDetails);
  const {loading, error, product} = productDetails;

  useEffect (() => {
    dispatch(listProductDetails(id));
  },[dispatch, id]);
      return(//code here)

first, remove all the 'match' related code. Replace match.params.id to id only, then make an id variable by const {id} = useParams();. Also make sure that useParams is imported.

Next in productActions.js file:

export const listProductDetails = (id) => async (dispatch) =>{
    try{
        dispatch({ type: PRODUCT_DETAILS_REQUEST});

        const {data} = await axios.get(`/api/products/${id}`);
        
        dispatch({
            type: PRODUCT_DETAILS_SUCCESS,
            payload: data,
            
        })
        
    }catch(error){
        dispatch({
            type: PRODUCT_DETAILS_FAIL,
            payload: error.response && error.response.data.message ? error.response.data.message : error.message,
        })
    }
}

Do not forget to add a '/' in the axios request: /api/products/${id}