Nick Kinlen
Nick Kinlen

Reputation: 1406

React/Redux - Pass variable to action

I'm new to Redux and working on a project using the Spotify API. I'm sending API calls and retrieving data about the currently playing song.

I have a separate Redux action that is attempting to grab other albums from the currently playing artist. In my App.js I can access the id of the artist via const id = this.props.currentlyPlaying.id

I want to pass this variable from App.js to my album action. The action contains the API call and looks like this:

import SpotifyWebApi from 'spotify-web-api-js';
import {id} from '../App.js';
const spotifyApi = new SpotifyWebApi();

export function fetchAlbums() {
  return function(dispatch) {
    dispatch({ type: "FETCH_ALBUMS_BY_ARTIST"});

    //'43ZHCT0cAZBISjO8DG9PnE'
    spotifyApi.getArtistAlbums(id)
      .then((response) => {
        dispatch({ type: "FETCH_ALBUMS_BY_ARTIST_FULFILLED", payload: response})
      })
      .catch((err) => {
        dispatch({ type: "FETCH_ALBUMS_BY_ARTIST_REJECTED", payload: err})
      });

  }
}

I've tried to import the id variable but I get an error. What is the proper way to pass a variable from a component to a Redux action? I've also tried to access id directly in the action via this.props, that doesn't work either.

Upvotes: 9

Views: 29790

Answers (3)

Sudhakar Krishnan
Sudhakar Krishnan

Reputation: 850

My config:

    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-redux": "^7.2.6",

We can pass values to dispatch function like this,

Slice file

import { createSlice } from '@reduxjs/toolkit'

export const rootSlice = createSlice({
    name: 'root',
    initialState: {
        posts: [
            { id: 1, title: "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body: "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" },
            { id: 2, title: "qui est esse", body: "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" },
            { id: 3, title: "ea molestias quasi exercitationem repellat qui ipsa sit aut", body: "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut" },
        ],
    },
    reducers: {
        deletePost: (state, action) => {
            console.log("state: " + state.posts)
            console.log("action: " + action.payload.id)
            console.log("action: " + action.payload.extra_val)
            // to do
            let newPost = state.posts.filter(post => {
                return action.payload.id !== post.id
            })
            return {
                ...state,
                posts: newPost
            }
        },
    },
})

// Action creators are generated for each case reducer function
export const { deletePost } = rootSlice.actions

export default rootSlice.reducer

Post file

import React from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux'
import { deletePost } from '../reducers/rootSlice'

const Post = () => {
    let navigate = useNavigate();
    let { post_id } = useParams();
    const posts = useSelector((state) => state.root.posts);
    var singPost = (id) => posts.find(obj => obj.id === parseInt(id))
    const dispatch = useDispatch()

    const handleClick = (id) => {
        dispatch(deletePost({ id, extra_val: 'ok-1' }));
        navigate("/");
    }

    const post = (id) => {
        var sp = singPost(id);
        return sp ? (
            <div className="post">
                <h4 className="center">{sp.title}</h4>
                <p>{sp.body}</p>
                <button onClick={() => handleClick(sp.id)}>deletePost</button>
            </div>
        ) : (
            <div className="center">Loading posts...</div>
        );
    }
    return (
        <div className="container">
            {post(post_id)}
        </div>
    );
}

export default Post;

Reference:

Upvotes: 2

Mark Small
Mark Small

Reputation: 414

Don't try to import the id, pass it as a parameter when calling the fetchAlbums action.

Something like:

ACTION:

export const fetchAlbums = (id) => async dispatch => {
  dispatch({ type: "FETCH_ALBUMS_BY_ARTIST"});

  //'43ZHCT0cAZBISjO8DG9PnE'
  spotifyApi.getArtistAlbums(id)
    .then((response) => {
      dispatch({ type: "FETCH_ALBUMS_BY_ARTIST_FULFILLED", payload: response})
    })
    .catch((err) => {
      dispatch({ type: "FETCH_ALBUMS_BY_ARTIST_REJECTED", payload: err})
    });
}

USING ACTION:

This will bind a function to call the fetchAlbums function, allowing you to pass parameters instead of the click event.

<button onClick={() => fetchAlbums(id)}>Fetch Album</button>

Upvotes: 13

Guillermo Quiros
Guillermo Quiros

Reputation: 441

What you need to do is when you call the action from your component is to pass th id to the action function.Like this: I will also recommend you to use redux-thunk middleware to handle a-asynchronous actions.

export function fetchAlbums(id) {
  return function(dispatch,id) {
    dispatch({ type: "FETCH_ALBUMS_BY_ARTIST"});

    //'43ZHCT0cAZBISjO8DG9PnE'
    spotifyApi.getArtistAlbums(id)
      .then((response) => {
        dispatch({ type: "FETCH_ALBUMS_BY_ARTIST_FULFILLED", payload: response})
      })
      .catch((err) => {
        dispatch({ type: "FETCH_ALBUMS_BY_ARTIST_REJECTED", payload: err})
      });

  }
}

Upvotes: 2

Related Questions