0

rootReducer

import { combineReducers } from "redux";
import mods from "./mods.js";

export default combineReducers({
    mods
})

reducers/mods.js

import { GET_MODS, GET_SPECIFC_MOD } from "../actions/types"

const initialState = {
    mods: [],
    currMod: []
}

export default function(state = initialState, action) {
    switch(action.type) {
        
        case GET_MODS:
            return {
                ...state,
                mods: action.payload
            }

        case GET_SPECIFC_MOD:
            return {
                ...state,
                currMod: action.payload
            }
        default:
            return state
    }
}

actions/mods.js

import axios from 'axios'
import { GET_MODS, GET_SPECIFC_MOD } from './types'

// get the mods
export const getMods = () => dispatch => {
    axios.get('http://localhost:8000/api/mods')
        .then(res => {
            dispatch({
                type: GET_MODS,
                payload: res.data
            })
        }).catch(err => console.log(err))
}

// get single mod
export const getSpecificMod = (title) => dispatch => {
    axios.get(`http://localhost:8000/api/mods/${title}`)
        .then(res => {
            dispatch({
                type: GET_SPECIFC_MOD,
                payload: res.data
            })
        }).catch(err => console.log(err))
}

components/download.js

import React from 'react'
import { useState, useEffect } from 'react'
import { connect } from 'react-redux'
import { getSpecificMod } from '../actions/mods'

const Download = () => {
    useEffect(() => {
        const title = window.location.pathname.split('/')[3]
        getSpecificMod(title)
    })

    return (
        <></>
    )
}

const mapStateToProp = state => ({
    currMod: state.mods.currMod
})

export default connect(mapStateToProp, getSpecificMod)(Download)

Response from backend

GET http://localhost:8000/api/mods/function(){return!window.__REDUX_DEVTOOLS_EXTENSION_LOCKED__&&a.dispatch.apply(a,arguments)}

Basically the user clicks on a mod and gets sent to the download section that is handled by 'download.js' the component ('download.js') renders it and reads the window.location to retrieve the title, with redux I want to get the mod so i made a function that takes the title and sends the request 'getMod(title)' but for some reason it is throwing horrible errors that I dont understand, any help is appreciated!

4
  • Hi, did you wrap the root component with <Provider>? Commented Aug 9, 2021 at 18:29
  • Oh, seems there is something wrong. use react hooks like useDispatch and useSelector on the function components. Commented Aug 9, 2021 at 18:31
  • What kind of horrible errors you are getting. And can you console.log title inside your function getSpecificMod to see what is your final url that you are making request to. Simply just console.log(http://localhost:8000/api/mods/${title}) this. Commented Aug 9, 2021 at 18:31
  • You are not dispatching the action properly in your component. Right now you are actually just calling the action creator function from your imports and not using any of the props from the connect HOC. Commented Aug 9, 2021 at 18:36

1 Answer 1

1

You are not dispatching the action properly in your component. Right now you are actually just calling the getSpecificMod action creator function from your imports. Your Download component doesn't read anything from props so it is ignoring everything that gets created by the connect HOC.

If you want to keep using connect, you can fix it like this:

import React, { useEffect } from 'react'
import { connect } from 'react-redux'
import { getSpecificMod } from '../actions/mods'

const Download = ({currMod, getSpecificMod}) => {
    const title = window.location.pathname.split('/')[3]

    useEffect(() => {
        getSpecificMod(title)
    }, [title])

    return (
        <></>
    )
}

const mapStateToProps = state => ({
    currMod: state.mods.currMod
})

export default connect(mapStateToProps, {getSpecificMod})(Download)

We are now accessing the bound action creator as a prop of the component. mapDispatchToProps is an object which maps the property key to the action.

But it's better to use the useDispatch hook:

import React, { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { getSpecificMod } from '../actions/mods'

const Download = () => {

    const currentMod = useSelector(state => state.mods.currMod);

    const dispatch = useDispatch();

    const title = window.location.pathname.split('/')[3]

    useEffect(() => {
        dispatch(getSpecificMod(title));
    }, [title, dispatch]);

    return (
        <></>
    )
}

export default Download;

There might be some confusion on terminology here. Your getSpecificMod function is a function which takes dispatch as an argument but it is not a mapDispatchToProps. It is a thunk action creator.

Make sure that you have redux-thunk middleware installed in order to handle this type of action. Or better yet, use redux-toolkit.


Your useEffect hook needs some sort of dependency so that it knows when to run. If you only want it to run once you can use an empty array [] as your dependencies. If you don't specify the dependencies at all then it will re-run on every render.

Does the pathname change? If so, how do you know when? You might want to add an event listener on the window object. Or consider using something like react-router. But that is a separate question.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.