I have a variable that I believe is correctly written to my Redux store using a Redux action and reducer. But for some reason it never becomes part of the props on a React page. What could be the cause, given the code below?
I would expect this.props.transactionDetails
and this.state.trans_status
to be available within the render
code block. The Redux store is functioning correctly for other variables/pages.
React Page:
import { get_details } from "../../../appRedux/actions/transAction";
class DonePage extends Component {
constructor(props) {
super(props);
this.state = {
showLoader: true,
transactionDetails: "",
trans_status: "",
};
}
async componentDidMount() {
await this.props.get_details('abc1234');
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.transactionDetails !== this.props.transactionDetails) {
console.log("Inside ComponentDidUpdate");
// It never arrives here, perhaps suggesting the prop is never created in the store?
this.setState({
trans_status: this.props.transactionDetails.trans_status,
});
}
}
render() {
console.log(JSON.stringify(this.state.trans_status);
// returns "" instead of the value of the redux action/reducer
console.log(JSON.stringify(this.props.transactionDetails);
// returns undefined instead of the value of the redux action/reducer
// What am I doing wrong? Why am I not getting the transactionDetails here?
}
}
const mapStateToProps = (state) => {
return {
settings: state.settings,
// the settings property works fine in this component
transactionDetails: state.transactionDetails,
};
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators(
{get_details}, dispatch
);
};
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(DonePage));
Redux Action:
export const get_details = (trans_id) => {
let token = getAuthToken();
return (dispatch) => {
axios
.get(`${url}/get_details/${trans_id}`, {
headers: { Authorization: `${token}` },
})
.then((res) => {
if (res.status === 200) {
console.log(JSON.stringify(res.data.data);
// returns {"trans_status":"paid","trans_due":"0"}
return dispatch({
type: DETAILS_SUCCESS,
payload: res.data.data,
});
} else {
return dispatch({
type: DETAILS_ERROR,
payload: res.data.data,
});
}
})
}
}
Reducer:
import {
DETAILS_SUCCESS,
DETAILS_ERROR,
} from "../constants";
const initial_state = {
transactionDetails: [],
transactionDetailsError: "",
};
export default function transactionsReducer(state = initial_state, action) {
switch (action.type) {
case DETAILS_SUCCESS:
console.log(JSON.stringify(action.payload));
// returns {"trans_status":"paid","trans_due":"0"}
return { ...state, transactionDetails: action.payload };
case DETAILS_ERROR:
return { ...state, transactionDetailsError: action.payload };
default:
return state;
}
};
Update In the reducers index file (/reducers/index.js
) I have:
const reducers = combineReducers({
variousVariables: variablesReducer,
transactions: transactionsReducer,
});
It works if I change this to:
const reducers = combineReducers({
variousVariables: variablesReducer,
transactionDetails: transactionsReducer,
});
On the Page, within render
, this.props.transactionDetails
now returns data:
{"transData":[],"transactionDetails":{"transaction_status":"paid","transaction_amount_due":"0"},"transactionDetailsError":"","otherData":"", etc.}
So transactionDetails
is nested inside another transactionDetails
and I need to call this.props.transactionDetails.transactionDetails
or this.props.transactionDetails.transData
. However, I would like this to be this.props.transactions.transactionDetails
and this.props.transactions.transData
.
Can someone explain what is going on? I thought I could just name the keys in the reducers index file anything I like and that then defines the "path" of this.props.anythingilike
.
Why can I not just change the key in the reducers index file to get what I'm looking for? I guess I need to change something on the Page as well to make it the way I want? Because right now if I change the key in the reducers index file to transactions
, then this.props.transactions
is still undefined
on the Page, while if that key is transactionDetails
then this.props.transactionDetails
does return the correct data.
I found the solution to my question. As suggested by several people there was details about the store setup that were of importance, particularly the setup of the reducers and the use of combineReducers
.
The setup of my reducers included:
const reducers = combineReducers({
...,
transactions: transactionsReducer,
});
To make it work, on the Page I only needed to change:
1--this.props.transactionDetails
to this.props.transactions
(and this.props.transactions.transactionDetails
if needed.
2--The last line in the code block below needed to be transactions: state.transactions
const mapStateToProps = (state) => {
return {
settings: state.settings,
transactionDetails: state.transactionDetails,
};
};