'Passing the state from a Redux Slice to the Component is giving me undefined

I'm doing this in other components very similarly, except this one takes a parameter of title_id. I am getting my data to fetch when I check the Redux DevTool and I console logged the payload from the mediaSlice too, but the useSelector in my Component is bringing nothing in and not updating my state. Can you help me figure out what exactly is it that I am messing up on so my selector can send the payload to my Component's state?

I made comments/questions in my code below where I think my problem areas are.

Here is my mediaSlice.js

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";

const KEY = process.env.REACT_APP_API_KEY
const BASE_URL = process.env.REACT_APP_BASE_URL
const SINGLE_MEDIA_API = `${BASE_URL}/titlestest`

const initialState = {
  media:[],
  status: 'idle', 
  error:null
}

export const fetchSingleMediaTitle = createAsyncThunk(
  'medias/fetchSingleMediaTitle', 
  async (mediaId) => { // <-- would this be where I declare the param key I am using?
    try {
      const response = await axios.get(
        SINGLE_MEDIA_API,
        {
          headers: {
            'Content-Type': 'application/json',
            'X-API-KEY': KEY,
          },
          params: {
            titleId: mediaId,
          }
        }
      )

      return response.data.Item;
    } catch (error) {
      console.error('API call error:', error.message);
    }
  }
)

const mediaSlice = createSlice({
  name: 'medias',
  initialState,
  reducers:{},
  extraReducers(builder) {
    builder
      .addCase(fetchSingleMediaTitle.pending, (state, action) => {
        state.status = 'loading'
      })
      .addCase(fetchSingleMediaTitle.fulfilled, (state, action) => {
        state.status = 'succeeded'
        const loadedMedia = action.payload
        state.media = loadedMedia
              console.log("loadedMedia: ", loadedMedia); // this is successfully printing the data object
      })
      .addCase(fetchSingleMediaTitle.rejected, (state, action) => {
        state.status = 'failed'
        state.error = action.error.message
      })
  }
})

// SELECTORS
export const selectSingleMedia = (state, mediaId) => state.media.media.find(item => item.title_id === mediaId); //this is where I am suspecting the problem is in

export const getMediaStatus = (state) => state.media.status;
export const getMediaError = (state) => state.media.error;

export default mediaSlice.reducer

And my Component. Reduced for brevity

import React, { useState, useEffect, useRef, Fragment } from 'react'
import { useSelector, useDispatch } from 'react-redux';
import { getMediaError, getMediaStatus, selectSingleMedia, fetchSingleMediaTitle } from '../../features/medias/mediaSlice'
import { useParams, useHistory } from "react-router-dom";

const SingleMediaTitle = () => {
  //STATES
  const [data, setData] = useState([]); 

  const {mediaId} = useParams();
  const dispatch = useDispatch();
  const media = useSelector((state, mediaId) => selectSingleMedia(state, mediaId)) //This is a suspect line too
  const mediaStatus = useSelector(getMediaStatus)
  const error = useSelector(getMediaError)
    
  useEffect(() => { 
    if (mediaStatus === 'idle') {
      dispatch(fetchSingleMediaTitle(mediaId))
    }
    setData(media);
    console.log("media: ", media); // This is undefined

  }, [mediaId, media, mediaStatus, dispatch])


  let content;

  if (mediaStatus === 'loading') {
    content = <Box className="loading">
                <Typography variant="subtitle2">Loading ..</Typography>
              </Box>
  } else if (mediaStatus === 'succeeded') {
    content = <Box>
                {media.content_source} //Though redux succeeded, this is not displaying 
              <Box/>  
  } else if (mediaStatus === 'failed') {
    content = <Box className="loading">
                <Typography variant="subtitle2">{error}</Typography>
              </Box>
  } 

  return (
    <Box sx={{p:3, pt:9}}> {content} </Box>      
  )
}

export default SingleMediaTitle

I really appreciate your help. Being the only front end dev in house is tough lol



Solution 1:[1]

I can spot 2 things that can cause the problem:

1) Your selectors

Since useSelector will get the entire state, you have to dig into your slice first and then deeper into the media data. Since the name of slice is medias this should be the first one. According to this your selectors should be:

// SELECTORS
export const selectSingleMedia = (state, mediaId) => state.medias.media.find(item => item.title_id === mediaId);

export const getMediaStatus = (state) => state.medias.media.status;
export const getMediaError = (state) => state.medias.media.error;
2) The single media selector
  const {mediaId} = useParams();
  const media = useSelector((state, mediaId) => selectSingleMedia(state, mediaId))

Since mediaId exists in the scope of the selector you should not expect it as an argument of the selector and just pass it as parameter to selectSingleMedia like below:

  const {mediaId} = useParams();
  const media = useSelector((state) => selectSingleMedia(state, mediaId))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 fgkolf