Reputation: 141
So I have been trying to solve this problem in a couple of ways but none of them really worked. I use Redux with React so I want to use the date from the store in my react component.
The problem is, the data is not the on the first render, so the variable I am trying to access is undefined.
const { errors } = this.props;
let errorList = null;
if(errors){
errorList = Object.keys(this.props.error).map(function(key) {
return <li className = "list-group-item list-group-item-danger" key = {errors[key]}> {errors[key]}</li>;
});
}
I tried to make a const out of the props value I want to use, but that doesn't help since that becomes undefined as well.
I tried writing a simple if statement to check if the value is undefined, but still no luck:
if(this.props.errors && typeof this.props.errors !== 'undefined'){ ... }
In my reducer, I have an initial state, so I am not sure why it becomes undefined despite that. Maybe I am just doing the initialization wrong.. Here is my reducer:
import { SET_ERRORS } from '../actions/creators/types';
const initialState = {}
export default function reducerError(state = initialState, action){
switch(action.type){
case SET_ERRORS:
return action.payload;
default:
return state;
}
}
I searched for a solution, some of the suggested using componentWillReceiveProps, but that is deprecated, and if there is a better solution, I wouldn't want to use it.
How can I make sure the code only runs if the props arrived? I am using this one in a form to get back error messages, but I have different ones too, and they don't really work either. Some of them does, but I am doing the exact same thing here, and this just doesn't.
Upvotes: 1
Views: 361
Reputation: 375
This is how I use Redux to extract state from store and use within a component. This likely won't solve all of your problems, but will show a concise example.
import React, {useEffect} from 'react'
import {useDispatch, useSelector} from "react-redux";
import getStuffFromDB from "../actions/getStuff"
const Example = () => {
const dispatch = useDispatch();
const stuffFromState = useSelector(state => state.stuff); // stuff is part of our state in the store
const {error, loading, stuff} = stuffFromState; // destructure state
useEffect(()=>{
dispatch(getStuffFromDB()) // get stuff from the database
}, [dispatch])
return (
<>
{/* Show loader if loading */}
{loading && <Loader />}
{/* Show error message if exists */}
{error && <Message severity="error">{error}</Message>}
<div>
<p>{stuff}</p>
</div>
</>
)
}
export default Example
Example reducer (note I am using thunk middleware):
export const getStuffReducer = (
state = { stuff: [] },
action
) => {
switch (action.type) {
case STUFF_FROM_DATABASE_REQUEST:
return { loading: true };
case STUFF_FROM_DATABASE_SUCCESS:
return {
loading: false,
stuff: action.payload,
};
case STUFF_FROM_DATABASE_FAIL:
return { loading: false, error: action.payload };
default:
return state;
}
};
Example action:
export const getStuffFromDB = () => async dispatch => {
try {
dispatch({ type: STUFF_FROM_DATABASE_REQUEST });
const { data } = await axios.get("/api/stuff");
dispatch({ type: STUFF_FROM_DATABASE_SUCCESS, payload: data });
} catch (error) {
dispatch({
type: STUFF_FROM_DATABASE_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
});
}
};
Store setup:
import { createStore, combineReducers, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
const reducer = combineReducers({
stuff: getStuffReducer,
});
// Set initial state
const initialState = {};
// Configure thunk middleware
const middleware = [thunk];
// Configure store
const store = createStore(
reducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;
Upvotes: 0
Reputation: 141
I had a typo at
errorList = Object.keys(this.props.error).map(function(key) {
That this.props.error should have been 'errors'.
Upvotes: 1