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;
})
}
}
Related
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
Hello i am just starting to learn redux and am currently having a problem, i have an api i want to get information from and use it in different components i would appreciate if you help me
import React from 'react';
import { render } from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import thunk from "redux-thunk";
import { createLogger } from "redux-logger";
import { BrowserRouter} from "react-router-dom";
import Reducer from './Reducers';
import App from './App';
import fetchSimcards from './Actions/fetchSimcards';
const middleware = [ thunk ];
middleware.push( createLogger() );
const store = createStore(
Reducer
applyMiddleware(...middleware),
);
import * as serviceWorker from './serviceWorker';
store.dispatch(fetchSimcards());
render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root')
);
serviceWorker.unregister();
and this is my action file
import * as type from '../Constans/ActionTypes';
export const ReceiveSimcards = Simcards => ({
type: type.RECEIVE_SIMCARDS,
Simcards
});
this is my reducer file
import { combineReducers } from "redux";
const Simcards = ( state = {}, action ) => {
console.log( state, action );
return state;
};
export default combineReducers({
Simcards
});
this is my container file for simcards
import React, {Component} from 'react';
import SimcardList from "../Component/SimcardList";
import { connect } from "react-redux";
class SimcardContainer extends Component {
render() {
const Simcards = this.props;
return (
<div>
<SimcardList title={"Simcards"} />
<div className="TableNumberItem">{Simcards.SimCardNumber}</div>
<div className="TableNumberItem">{Simcards.SimCardDescription}</div>
<div className="TableNumberItem">{Simcards.TeammatePrice}</div>
</div>
);
}
}
export default connect()(SimcardContainer);
and i want show this container in home page
With redux, you should call all API and handling logic code in action.
Example with action fetchAPI:
export const fetchAPI = () = async dispatch => {
let response = null;
try {
response = await axios.get('api/...')
// Example use axios
dispatch(fetchSuccess(response.data))
// To handle in reducer with redux
} catch (error) {
... Handle error here
}
}
const fetchSuccess = data => ({
type: FETCH_SUCCESS,
data: response.data
})
And in your component, you can use connect to get state and action:
import { bindActionCreators } from 'redux';
import React, { Component } from 'react';
import SimcardList from "../Component/SimcardList";
import { connect } from "react-redux";
import * as _Actions from '../../action/index'
class SimcardContainer extends Component {
componentDidMount(){
const { fetchAPI } = this.props.actions;
**fetchAPI();** // Call API here
}
render() {
const { stateReducer} = this.props;
console.log(stateReducer)
// Here, you will see data that you handled in reducer
// with action type FETCH_SUCCESS
// You should remember data that you fetch from API is asynchronous,
// So you should check like that `data && {do any thing heree}`
return (
<div>
<SimcardList title={"Simcards"} />
<div className="TableNumberItem">{Simcards.SimCardNumber}</div>
<div className="TableNumberItem">{Simcards.SimCardDescription}</div>
<div className="TableNumberItem">{Simcards.TeammatePrice}</div>
</div>
);
}
}
const mapStateToProps = state => ({
stateReducer: state
})
const mapDispatchToProps = dispatch => ({
actions: bindActionCreators(_Actions, dispatch)
})
export default connect(mapStateToProps, mapDispatchToProps)(SimcardContainer)
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);
...
}
When authentication is done I can see the actions updating and the reducer updating - but then mapstatetoprops does not do anything with the new reducer state
The Store keeps logging the same state(initial state) on every update
import React from 'react';
import { bindActionCreators } from 'redux'
import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth';
import { Redirect } from 'react-router-dom'
import firebase from 'firebase';
import { connect } from 'react-redux';
import { signIn, signOut } from '../reducer/actions'
import { auth } from '../firebase'
class LoginPage extends React.PureComponent {
// Configure FirebaseUI.
uiConfig = {'FirebaseUI Config'}
componentDidMount = () => {
auth.onAuthStateChanged((user) => { // gets user object on authentication
console.log('OnAuthStateChanged', user)
console.log('Check If Props Change in AuthChange', this.props.isauthed)
if (user) {
this.props.signIn(user)
} else {
this.props.signOut(user)
}
});
}
render() {
console.log('Check If Props Change in Render', this.props.isauthed)
if (!this.props.isauthed) {
return (
<div>
<h1>My App</h1>
<p>Please sign-in:</p>
<StyledFirebaseAuth uiConfig={this.uiConfig} firebaseAuth={firebase.auth()} />
</div>
);
}
return (
<Redirect to='/' />
)
}
}
export default (LoginPage);
JS that should dispatch and update the props
import { connect } from 'react-redux';
import { signIn, signOut } from '../reducer/actions'
import { bindActionCreators } from 'redux'
import LoginPage from './LoginPage';
const mapStateToProps = (state) => {
console.log('LOGINmapstatetoprops', state.Authed)
return {
isauthed: state.Authed.isauthed,
}
}
const mapDispatchToProps = (dispatch) => {
console.log('LOGINmapDISPATCHoprops')
return bindActionCreators({signIn, signOut}, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(LoginPage);
The reducer
import LoginPage from '../components/LoginPage';
import firebase from 'firebase';
const initialState = {
isauthed: false,
error: ''
}
const AuthReducer = (state = initialState, action) => {
console.log('this is an action', action)
switch (action.type) {
case 'IsSignedIn':
return {
...state,
isauthed: action.payload
}
break;
case 'IsNotSignedIn':
return {
...state,
isauthed: action.payload
}
break;
default: return state
}
}
export default AuthReducer;
This is the actions file
export const signIn = (user) => {
console.log('this is from actions', user)
return {
type: 'isSignedIn',
payload: true
}
}
export const signOut = (user) => {
console.log(user)
return {
type: 'isNotSignedIn',
payload: false
}
}
Redux Store
import { createStore } from 'redux';
import logger from 'redux-logger';
import { createEpicMiddleware } from 'redux-observable';
import {AllReducers} from './reducer/index';
//import rootEpic from './modules/rootEpic';
//const epicMiddleware = createEpicMiddleware(rootEpic);
const store = createStore(AllReducers);
store.subscribe(() => {
console.log('storeupdated', store.getState())
});
export default store;
CombineReducers Function
import {combineReducers} from 'redux'
import {AuthReducer} from './AuthReducer'
import {UserReducer} from './UserReducer'
export const AllReducers = combineReducers({
Authed: AuthReducer
User: UserReducer
})
Seems like you have a typo error between 'isSignedIn' and 'IsSignedIn' (first letter differ)
You could avoid that by using a variable declared in a separated file. I like to call it types.js for the types of actions:
// types.js
export const IS_SIGNED_IN = 'isSignedInOrEvenWhateverButYouBetterKeepAClearName'
// (same with all your types)
And then you can import this variable in your other files. You won't have typos anymore!
P.S: you can find all these ideas in redux documentation
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 };
};