Good morning everyone,
I just set up redux on my react project. What i am willing to do is to get data when the component Dashboard is rendered. Data are expenses and incomes variables, which are the sum of all the expenses and incomes.
The problem i get is that my reducer is never triggered. I get no error in my console.
As you can see in actions/dashboard.js, i consoled log when the call to fetchdata is done, and is working correctly. but the call to setBalance does not.
In the reducers/dashboard.js, in the switch case, the default case is always triggered, it's like it does not find the action type.
My Component Dashboard.js
import React, {useEffect} from 'react'
import classes from './Dashboad.module.css'
import { Doughnut } from 'react-chartjs-2'
import {connect} from 'react-redux'
import * as actions from '../../store/actions/index'
const DashBoard = (props) => {
useEffect(() => {
props.onFetchData()
}, [])
// ----------------------------------- Hidden code to not overload the topic -------------------
const mapStateToProps = state => {
return {
incomes: state.incomes,
expenses: state.expenses
}
}
const mapDispatchToProps = dispatch => {
return {
onFetchData: () => dispatch(actions.fetchData),
}
}
export default connect(mapStateToProps,mapDispatchToProps)(DashBoard);
actions/index.js :
export {
fetchData
} from './dashboard'
actions/actionsTypes.js :
export const SET_BALANCE = 'SET_BALANCE'
actions/Dashboard.js
import * as actionsTypes from './actionsTypes'
import axios from '../../axios'
export const setBalance = (donnees) => {
console.log('setbalance')
return {
type: actionsTypes.SET_BALANCE,
donnees: donnees
}
}
export const fetchData = () => {
console.log('call fetchdata')
return dispatch => {
axios.get('/movements.json')
.then(response => {
dispatch(setBalance(response.data))
console.log(response.data)
})
.catch(error => console.log(error))
}
}
Reducers/Dashboard.js :
import * as actionsTypes from '../actions/actionsTypes'
const initialState = {
incomes: 0,
expenses: 0
}
const setBalance = (state, action) => {
let fetchedMvts = []
for(let key in action.donnees.data) {
fetchedMvts.push({...action.donnees.data[key]})
}
let sumIncome = 0;
let sumOutcome = 0;
fetchedMvts.forEach(element => {
let parsed = parseInt(element.amount, 10)
if(element.type === "income") {
sumIncome = sumIncome + parsed;
} else {
sumOutcome = sumOutcome + parsed;
}
})
return {...state, incomes: sumIncome, expenses: sumOutcome}
}
const reducer = (state= initialState, action) => {
console.log('TYPE', action.type)
switch (action.type) {
case actionsTypes.SET_BALANCE: return setBalance(state, action);
default:
console.log('problem')
return state;
}
}
export default reducer;
And, in case you need it, the index.js file of my app :
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux'
import { createStore, applyMiddleware} from 'redux'
import * as serviceWorker from './serviceWorker';
import RootReducer from './store/reducers/dashboard'
import thunk from 'redux-thunk'
const store = createStore(RootReducer, applyMiddleware(thunk))
ReactDOM.render(
<Provider store={store}>
<React.StrictMode>
<App />
</React.StrictMode>
</Provider>,
document.getElementById('root')
);
serviceWorker.unregister();
Thank you for your help guys
Have a nice day
Related
I'm calling api using redux-thunk. I would like to get the results contained in the action data
if I look at the console and see that the component has dispatched fetchTrending(), the promise is returned.
please help me how to get the results
TrendMovieContainer.jsx
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchTrending } from '../actions/index';
import Trending from '../components/Trending';
const TrendMovieContainer = () => {
const title = useSelector(state => state.resluts.title);
//undefined
const dispatch = useDispatch()
const data = dispatch(fetchTrending())
console.log(data); // Promise {<pending>}
return (
<Trending title={title}/>
)
}
export default TrendMovieContainer;
TrendMovie.jsx
import React from 'react';
const TrendMovie = ({ title, id, img }) => {
return (
<div className="movieBox">
<h3>{title}</h3>
<img src={img} alt={id}/>
</div>
)
}
export default TrendMovie;
action/index.js
import axios from 'axios';
const API_KEY = '224ce27b38a3805ecf6f6c36eb3ba9d0';
const BASE_URL = `https://api.themoviedb.org/3`
export const FETCH_TRENDING = 'FETCH_TRENDING';
export const fetchData = (data) => {
return {
type: FETCH_TRENDING,
data
}
}
export const fetchTrending = () => {
return (dispatch) => {
return axios.get(`${BASE_URL}/trending/all/week?api_key=${API_KEY}&language=en-US`)
.then(response => {
dispatch(fetchData(response.data))
})
.catch(error => {
throw(error);
});
}
}
reducer.js
import { FETCH_TRENDING } from '../actions/index';
export default function reducerTrending(state = [], action) {
switch (action.type) {
case FETCH_TRENDING:
return action.data;
default:
return state;
}
}
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import rootReducer from './reducers/index';
import { fetchTrending } from './actions/index';
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(rootReducer, composeEnhancer(applyMiddleware(thunk)));
console.log(store.dispatch(fetchTrending()));
ReactDOM.render(
<Provider store={store}><App /></Provider>,
document.getElementById('root'));
serviceWorker.unregister();
my store
You don't have to get data from the action. You have to get data from the reducer by using connect function or useSelector hook. As I see, you are trying to use hooks from react-redux library instead of connect function. Then you need to move the dispatching of fetchTrending action to useEffect hook and use useSelector hook to get data from the reducer:
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
...
const TrendMovieContainer = (props) => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchTrending());
}, []);
const data = useSelector(state => state.reducerTrending)
console.log(data);
...
}
I want to separate modules, so I tried to separate files in the src/store/modules directory.
To merge reducer modules, I use combineReducers() in modules/index.js.
Before separating these modules, modules/index.js file's code was modules/board.js.
Then I added board.js file. I moved code of index.js to board.js. Finally I added combineReducer() in index.js, but somehow it is not working.
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './containers/App';
import store from './store';
const rootElement = document.getElementById('root');
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
rootElement
);
src/containers/BoardContainer.js
import React from 'react';
import Board from '../components/Board';
import { connect } from 'react-redux';
import * as boardActions from '../store/modules/board';
class BoardContainer extends React.Component {
componentWillMount() {
this.props.handleReadBoards();
}
render() {
/* ... */
}
}
const mapStateToProps = (state) => {
return {
boardList: state.get('boardList')
};
}
const mapDispatchToProps = (dispatch) => {
return {
handleReadBoards: () => { dispatch(boardActions.readBoardList()) }
};
}
export default connect(mapStateToProps, mapDispatchToProps)(BoardContainer);
src/store/index.js
// redux
import { createStore, applyMiddleware, compose } from 'redux';
import reducers from './modules';
// redux middleware
import thunk from 'redux-thunk';
const store = createStore(reducers,
compose(applyMiddleware(thunk))
);
export default store;
src/store/modules/index.js
import { combineReducers } from 'redux';
import board from './board';
export default combineReducers({
board
});
src/store/modules/board.js
import { createAction, handleActions } from 'redux-actions';
import { Map, List } from 'immutable';
import * as boardApi from '../../lib/api/board';
// Action Types
const READ_BOARD_LIST = 'board/READ_BOARD_LIST';
// Action Creators
export const readBoardList = () => async (dispatch) => {
try {
const boardList = await boardApi.getBoardList();
dispatch({
type: READ_BOARD_LIST,
payload: boardList
});
} catch (err) {
console.log(err);
}
}
// initial state
const initialState = Map({
boardList: List()
})
// reducer
// export default handleActions({
// [READ_BOARD_LIST]: (state, action) => {
// const boardList = state.get('boardList');
// return state.set('boardList', action.payload.data);
// },
// }, initialState);
// reducer
export default function reducer(state = initialState, action = {}) {
switch (action.type) {
case READ_BOARD_LIST:
return state.set('boardList', action.payload.data);
default:
return state;
}
}
Your reducer now contains submodules. So that you have to state from which module you want to get the data: state.board.get('boardList').
You can try to setup redux tool to easy visualize your data inside redux.
const mapStateToProps = (state) => {
return {
boardList: state.board.get('boardList')
};
}
I'm having trouble retrieving data from the Redux store. Redux logger is showing the data but can't seem to get it to render. Below is the code for my container component and my action/reducer:
//COMPONENT:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchGrade } from '../../modules/smiles';
class Main extends Component {
componentDidMount() {
this.props.fetchSmile();
console.log(this.props);
}
render() {
const { smiles } = this.props;
return (
<div>
<h1>This is the Main Component</h1>
</div>
);
}
}
const mapStateToProps = state => {
return { smiles: state.smiles };
};
const mapDispatchToProps = dispatch => {
return {
fetchSmile: params => dispatch(fetchGrade(params))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Main);
//ACTION/REDUCER:
import axios from 'axios';
const ADD_GRADE = 'SMILES/ADD_GRADE';
export function reducer(state = {}, action) {
switch (action.type) {
case ADD_GRADE:
return {
...state,
grade: action.payload
};
default:
return state;
}
}
export const fetchGrade = () => {
return dispatch => {
axios
.get('/api/test')
.then(res => dispatch({ type: ADD_GRADE, payload: res.data }));
};
};
//STORE:
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
import logger from 'redux-logger';
import reducer from '../modules';
let store;
export function configureStore(state: {}) {
if (!store) {
store = createStore(
reducer,
state,
composeWithDevTools(applyMiddleware(logger, thunk))
);
}
return store;
}
//INDEX.JS:
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import './index.css';
import App from './components/App';
import registerServiceWorker from './registerServiceWorker';
import { configureStore } from './store';
window.store = configureStore();
render(
<Provider store={window.store}>
<App />
</Provider>,
document.getElementById('root')
);
registerServiceWorker();
I really don't know if this is complicated or an easy fix. I feel like I'm doing everything right but no luck.
You named your reducer, reducer:
export function reducer(state = {}, action) {
Seems that you forgot to access it from your reducer object. it should be something like this:
const mapStateToProps = state => {
return { smiles: state.reducer.smiles };
};
I am calling API in action and have to pass those action to reducer. But data from action is not passing to the reducer. I am not using combined-reducer either.
src/index.js is
import React from 'react';
import ReactDOM from 'react-dom';
import PrescriptionIndex from './components/prescriptionIndex.jsx';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import reducer from './reducer';
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<PrescriptionIndex />
</Provider>, document.getElementById("root")
)
This is my component PrescriptionIndex.jsx
import React, { Component } from 'react';
import { index_prescription } from '../action/index.js';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
class PrescriptionIndex extends Component {
constructor(props){
super(props);
this.state={
prescription: null
}
}
action_call(){
index_prescription();
}
render(){
this.state.prescription === null ? this.action_call() : null
return(
<div>
PrescriptionIndex
</div>
)
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({index_prescription}, dispatch)
}
function mapStateToProps( state ){
return {
profiles: state
}
}
export default connect(mapStateToProps, mapDispatchToProps)(PrescriptionIndex);
I am calling index function as index_prescription(); in action_call().
And my action is
import {ADD_PRESCRIPTION} from '../constant.js';
import axios from 'axios';
import dispatch from 'axios';
export const index_prescription = () => {
const base_url= "http://localhost:3000/api/v1/";
const fetch_url = `${base_url}/prescriptions`;
axios.get(fetch_url)
.then(response => {
dispatch({type: ADD_PRESCRIPTION, details: response.data})
})
}
Reducer is
import {ADD_PRESCRIPTION} from '../constant.js';
const profiles = (state=[], action) => {
let profiles = null;
switch(action.type){
case ADD_PRESCRIPTION:
profiles = [...state, action.details]
return profiles;
default:
return state;
}
}
export default profiles;
constant.js is
export const ADD_PRESCRIPTION = "ADD_PRESCRIPTION";
I have verified all the questions, but cant able to study whats going wrong in my code.Thanks in advance.
You miss following code..
import {ADD_PRESCRIPTION} from '../constant.js';
import axios from 'axios';
import dispatch from 'axios';
export const index_prescription = () => {
return dispatch=>{
const base_url= "http://localhost:3000/api/v1/";
const fetch_url = `${base_url}/prescriptions`;
axios.get(fetch_url)
.then(response => {
dispatch({type: "ADD_PRESCRIPTION", details: response.data})
})
}
}
You are calling dispatch from axions? Is not part of react-redux?
If you use redux-promise-middleware you can do this:
import {ADD_PRESCRIPTION} from '../constant.js';
import axios from 'axios';
import dispatch from 'axios';
export const index_prescription = () => {
const base_url= "http://localhost:3000/api/v1/";
const fetch_url = `${base_url}/prescriptions`;
return {
type: "ADD_PRESCRIPTION",
details: axios.get(fetch_url)
.then(response => {
return response;
})
}
}
I have no idea what's going on here, I am using this technique correctly in React Native but won't work in ReactJS
Console just logs 'Outside' and never 'Inside', also no redux log is provided.
Application entry point:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import { Provider } from 'react-redux'
import { createStore, applyMiddleware, combineReducers } from 'redux'
import thunk from 'redux-thunk'
import logger from 'redux-logger'
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { authStateReducer } from './reducers/auth.js'
import { wishesStateReducer } from './reducers/wishes.js'
const root = combineReducers({
auth: authStateReducer,
wishes: wishesStateReducer
})
let store = createStore(root, applyMiddleware(thunk, logger))
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
registerServiceWorker();
Exporting root component like this:
function stateToProps(state) {
return { AUTH: state.auth, WISHES: state.wishes }
}
function dispatchToProps (dispatch) {
return {
registerAuthStateListener: () => { dispatch(registerAuthStateListener) },
fetchWishes: () => { dispatch(fetchWishes) }
}
}
export default connect(
stateToProps,
dispatchToProps
)(App);
And I am correctly calling the actions in 's componentDidMount():
componentDidMount () {
this.props.registerAuthStateListener()
this.props.fetchWishes()
}
Example thunk that is never activated:
import firebase from 'firebase'
export function fetchWishes () {
console.log("Outside")
return async (dispatch) => {
console.log("Inside")
let querySnapshot = await firebase.firestore().collection('wishes').get()
let newState = []
querySnapshot.forEach((wish) => {
newState.push({
id: wish.id,
...wish.data()
})
})
dispatch({
type: 'WISHES_FETCHED',
data: newState
})
}
}
Example reducer:
const INITIAL_WISHES_STATE = {
wishes: []
}
export function wishesStateReducer (state = INITIAL_WISHES_STATE, action) {
switch (action.type) {
case 'WISHES_FETCHED':
return {
wishes: action.data
}
default:
return state
}
}
function dispatchToProps (dispatch) {
return {
registerAuthStateListener: () => { dispatch(registerAuthStateListener()) },
fetchWishes: () => { dispatch(fetchWishes()) }
}
}
I wasn't calling the thunk action creators.
Everything else in your code looks good but I'm not too sure about this part:
return async (dispatch) => {
Try changing that to:
return (dispatch) => {