React-Redux-thunk props.fetchData is not a function - reactjs

I am trying to use Redux in my app, but something went wrong and I am currently get a mistake as props.fetchData is not a function. I tried to do it with useEffect but it did not work too.
My provider is set in App.js where I create store and give to other components
My App Code
export function Header(props) {
console.log(props)
props.fetchData('https://api.coincap.io/v2/assets');
return (
<ul>
{props.items.map((item) => (
<li key={item.id}>
{item.name}
</li>
))}
</ul>
);
}
const mapStateToProps = (state) => {
return {
items: state.items,
hasErrored: state.itemsHasErrored,
isLoading: state.itemsIsLoading
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: (url) => dispatch(itemsFetchData(url))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Header);
my store
export default function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
applyMiddleware(thunk)
);
}
my actions
export function itemsHasErrored(bool) {
return {
type: 'ITEMS_HAS_ERRORED',
hasErrored: bool
};
}
export function itemsIsLoading(bool) {
return {
type: 'ITEMS_IS_LOADING',
isLoading: bool
};
}
export function itemsFetchDataSuccess(items) {
return {
type: 'ITEMS_FETCH_DATA_SUCCESS',
items
};
}
export function itemsFetchData(url) {
return (dispatch) => {
dispatch(itemsIsLoading(true));
fetch(url)
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
dispatch(itemsIsLoading(false));
return response;
})
.then((response) => response.json())
.then((items) => dispatch(itemsFetchDataSuccess(items.data)))
.catch(() => dispatch(itemsHasErrored(true)));
};
}
reducers
export default combineReducers({
items,
itemsHasErrored,
itemsIsLoading
});
export function itemsHasErrored(state = false, action) {
switch (action.type) {
case 'ITEMS_HAS_ERRORED':
return action.hasErrored;
default:
return state;
}
}
export function itemsIsLoading(state = false, action) {
switch (action.type) {
case 'ITEMS_IS_LOADING':
return action.isLoading;
default:
return state;
}
}
export function items(state = [], action) {
switch (action.type) {
case 'ITEMS_FETCH_DATA_SUCCESS':
return action.items;
default:
return state;
}
}

Related

Uncaught TypeError: this.props.getData is not a function

Not able to call function inside a component, provided by Redux.
This is my Container component
export class HomeContainer extends React.Component {
render() {
return(
<Home
getData={ this.props.getData }
/>
)
}
}
const mapStateToProps = state => {
return state;
}
const mapDispatchToProps = dispatch => {
return bindActionCreators({
getData: getCountriesList.getCountriesByISO
}, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(HomeContainer);
I am calling that redux function inside the component using
componentDidMount() {
this.props.getData();
}
This is my Action
export function getCountriesByISOData() {
return (dispatch) => {
dispatch(toggleLoading(true));
return fetch('/api/countries', {
method: 'GET',
}).then(res => {
if(res.status === 200) {
return res.json().then(res=> {
console.log(res)
dispatch(toggleLoading(false));
dispatch(isSuccess(res));
})
} else {
dispatch(toggleLoading(false));
dispatch(isError(res.statusText));
}
}).catch(error => {
dispatch(toggleLoading(false));
dispatch(isError(error));
})
}
}
and this is my reducer
let defaultState = {
isLoading: false,
data: [],
error: ''
}
const getCountriesByISOReducer = (state=defaultState, action) => {
if(action.type === 'COUNTRIES_ISO_TOGGLE_LOADING') {
return {
...state,
isLoading: action.isLoading
}
}
if(action.type === 'COUNTRIES_ISO_IS_ERROR') {
return {
...state,
error: action.error
}
}
if(action.type === 'COUNTRIES_ISO_IS_SUCCESS') {
return {
...state,
data: [...state.data, action.success]
}
}
return state;
}
export default getCountriesByISOReducer;
This is my root reducer
export default combineReducers({
globalConfirmedCases: globalConfirmedCasesReducer,
dailyStatsByDate: getDailyStatsByDateReducer,
dailyStats: getDailyStatsReducer,
getCountriesByISO: getCountriesByISOReducer,
getCountriesStats: getCountriesStatsReducer
});
What I am doing wrong here? Is there any naming conventions while writing reducers and actions and using it in the react context?

Dispatching action calls incorrect reducer

Summary
In order to learn Redux, I am incorporating some state, actions, reducers, and trying to see how they are used in React Components.
I have set up a test object...
const initialState = {
navigationCount : 0,
someNumber : 500,
someList : ['aa',22,'c5d6','45615'],
};
...and aim to:
increment the navigationCount by 1 when visiting pages
add or subtract from someNumber
push() & pop() elements from someList.
Versions
Currently using gatsby ^2.5.0, react ^16.8.6, and react-redux ^6.0.1.
Code
actions & reducers
import { combineReducers } from 'redux';
import {
PAGE_INCREMENT,
NUMBER_INCREASE,
NUMBER_DECREASE,
LIST_PUSH,
LIST_POP,
} from './actionTypes.js';
// state
const initialState = {
navigationCount : 0,
someNumber : 500,
someList : ['aa',22,'c5d6','45615'],
};
// action creators returning actions
export const pageIncrementer = navigationCount => {
return {
type: PAGE_INCREMENT,
navigationCount,
};
};
export const numberAdder = numberToAdd => {
return {
type: NUMBER_INCREASE,
numberToAdd,
};
};
export const numberMinuser = numberToMinus => {
return {
type: NUMBER_DECREASE,
numberToMinus,
};
};
export const listPusher = itemToAdd => {
return {
type: LIST_PUSH,
itemToAdd,
}
};
export const listPopper = () => {
return {
type: LIST_POP,
}
};
// reducers
const pageIncrementReducer = (state = initialState, action) => {
switch (action.type) {
case PAGE_INCREMENT:
return Object.assign({}, ...state, {
navigationCount: action.navigationCount+1
});
default:
return state.navigationCount;
}
};
const numberChanger = (state = initialState, action) => {
switch (action.type) {
case NUMBER_INCREASE:
return Object.assign({}, ...state, {
someNumber: state.someNumber+action.numberToAdd,
});
case NUMBER_DECREASE:
return Object.assign({}, ...state, {
someNumber: state.someNumber-action.numberToMinus,
});
default:
return state.someNumber;
};
};
const listChanger = (state = initialState, action) => {
switch (action.type) {
case LIST_POP:
return Object.assign({}, ...state, {
someList: state.someList.pop(),
});
case LIST_PUSH:
return Object.assign({}, ...state, {
someList: state.someList.push(action.itemToAdd),
});
default:
return state.someList;
}
}
// store
const rootReducer = combineReducers({
pageIncrementReducer,
numberChanger,
listChanger,
});
export default rootReducer;
React Component
import React from 'react';
import Layout from '../components/common/Layout.jsx';
import LandingBanner from '../components/landing/LandingBanner.jsx';
import LandingNavgrid from '../components/landing/LandingNavgrid.jsx';
import LandingApp from '../components/landing/LandingApp.jsx';
import { connect } from 'react-redux';
import {
PAGE_INCREMENT,
NUMBER_INCREASE,
NUMBER_DECREASE,
LIST_PUSH,
LIST_POP,
} from '../state/actionTypes';
class LandingPage extends React.Component {
constructor(props){
super(props);
this.state = {
appliedNum: 2000,
};
}
componentDidMount(){
// this.props.pageIncrement(); // => numberChanger returned undefined
// this.props.numberIncrease(4444); // => pageIncrementReducer returned undefined
// this.props.numberDecrease(4444); // => pageIncrementReducer returned undefined
// this.props.listPush(4444); // => pageIncrementReducer returned undefined
this.props.listPop();
}
render(){
return (
<Layout>
<LandingBanner/>
<LandingNavgrid/>
<LandingApp/>
</Layout>
)
}
}
const filterNumbers = (list=[]) => {
console.log('filterNumbers list: ', list);
return list.filter(listElement => !!Number(listElement));
};
const mapStateToProps = (state, ownProps) => {
return {
someNumber: state.someNumber,
someList: filterNumbers(state.someList),
navigationCount: state.navigationCount,
};
};
const mapDispatchToProps = (dispatch) => {
return {
pageIncrement: () => dispatch({ type: PAGE_INCREMENT }),
numberIncrease: () => dispatch({ type: NUMBER_INCREASE }),
numberDecrease: () => dispatch({ type: NUMBER_DECREASE }),
listPush: () => dispatch({ type: LIST_PUSH }),
listPop: () => dispatch({ type: LIST_POP }),
}
}
export default connect(
mapStateToProps,
mapDispatchToProps,
)(LandingPage);
Errors
redux.js:449 Uncaught Error: Given action "LIST_POP", reducer
"pageIncrementReducer" returned undefined. To ignore an action, you
must explicitly return the previous state. If you want this reducer to
hold no value, you can return null instead of undefined.
first of all, you always need to return state on the default switch case.
default:
return state;

componentDidUpdate not firing after redux state change

I have these Reducers:
const initialState = {
categories: [],
programms: {}
}
export const programmReducers = (state = initialState, action) => {
let programms = state.programms;
switch (action.type) {
case actionTypes.FETCH_CATEGORIES:
return Object.assign({}, state, {
categories: action.payload
})
case actionTypes.FETCH_PROGRAMM:
programms[action.payload.id] = action.payload;
console.log(programms);
return {
...state,
programms: Object.assign({}, programms)
}
case actionTypes.FETCH_PROGRAMM_COMPONENTS:
programms[action.programmId].components = action.payload;
console.log('Added Components')
return {
...state,
programms: programms
}
default:
return state
}
}
The last one (FETCH_PROGRAMM_COMPONENTS) adds an array to an object in the programm object. This works but somehow it won't fire componentDidUpdate in my component. It works for FETCH_PROGRAMM though.
class ProgrammPage extends Component {
static async getInitialProps({ store, query: {id} }) {
let programm;
if (!store.getState().programm.programms[id]) {
console.log('Programm not! found');
programm = await store.dispatch(loadProgramm(id));
await store.dispatch(loadProgrammComponents(id));
} else {
programm = store.getState().programm.programms[id];
console.log('Programm found')
}
return {
// programm: programm
programmId: id
}
}
componentDidUpdate(prevProps) {
console.log('UPDATE', this.props, this.props.programm.components.length)
if (!prevProps.user && this.props.user) {
this.props.loadProgrammComponents(this.props.programmId);
}
}
render() {
return (
<div>
<h1>Programm</h1>
<h2>{this.props.programm.name}</h2>
<h2>{this.props.programm.id}</h2>
<h3>Components: {this.props.programm.components ? this.props.programm.components.length : 'None'}</h3>
<br></br>
<h1>User: { this.props.user ? this.props.user.uid : 'None'}</h1>
<button onClick={() => this.props.loadProgramm('ProgrammLevel2')}>Load Programm</button>
<button onClick={() => this.props.loadProgrammComponents(this.props.programmId)}>Load Components</button>
</div>
)
}
}
function mapStateToProps(state) {
return {
programm: state.programm.programms['ProgrammLevel1'],
programms: state.programm.programms,
user: state.auth.user
}
}
const mapDispatchToProps = dispatch => bindActionCreators({
loadProgrammComponents,
loadProgramm
}, dispatch)
export default connect(
mapStateToProps,
mapDispatchToProps
)(ProgrammPage)
You returning the same reference.
Try returning a copy of programms array: [...programms] ( or Object.assign() if it's an Object).
case actionTypes.FETCH_PROGRAMM_COMPONENTS:
programms[action.programmId].components = action.payload;
console.log('Added Components')
return {
...state,
programms: [...programms] // <-- Return new state
}

Redux how dispatch multiple action types with fetch method

I'm trying to make api call with fetch method from Redux, i create some action types like fetch_start, fetch_success and fetch_failed.
but i cant my reducer nothing return to me. When i check redux dev tool there is 3 action types too working. Where i mistake?
i'm using thunk, redux
here is my component:
class SignInComponent extends Component {
signIn = () => {
this.props.signIn()
}
render() {
return (
<Row className="justify-content-md-center">
<Col lg={4}>
<button type="button" onClick={this.signIn}>
</button>
</Col>
</Row>
)
}
}
const mapStateToProps = state => ({
users: state.users
})
function mapDispatchToProps(dispatch) {
return {
signIn: bindActionCreators(signIn, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SignInComponent)
here is my reducer:
import { SIGNIN_START, SIGNIN_SUCCESS, SIGNIN_FAILED } from '../../actions/Auth/SignIn'
let initialState = []
export default (state = initialState, action) => {
switch (action.type) {
case SIGNIN_START:
return console.log('start')
case SIGNIN_SUCCESS:
return console.log("success")
case SIGNIN_FAILED:
return console.log("fail")
default:
return state
}
}
here is my action:
export const SIGNIN_START = 'SIGNIN_START';
export const SIGNIN_SUCCESS = 'SIGNIN_SUCCESS';
export const SIGNIN_FAILED = 'SIGNIN_FAILED';
export const signIn = () => {
return(dispatch) => {
dispatch({
type: SIGNIN_START
})
fetch('https://api.com/signIn')
.then((response) => {
dispatch({
type: SIGNIN_SUCCESS
})
})
.catch((err) => {
dispatch({
type: SIGNIN_FAILED
})
})
}
}
you have to return the new state in the reducer for each action
return console.log();
will simply returns undefined.
change it to
switch (action.type) {
case SIGNIN_START:
console.log('start')
return [...state];
case SIGNIN_SUCCESS:
console.log("success")
return [...state];
case SIGNIN_FAILED:
console.log("fail");
return [...state];
default:
return state
}

Respond to a Single Redux Action in Multiple Reducers redux

I am using multiple reducers in my project and then combining them with combineReducers() function and have all actions in single file. when i dispatch the action, it is returning me state values to undefined. I think It can't find out because of multiple reducerse. But when i use single reducer file. It is working fine. Can anyone please tell me what the issue.It is how i am combining the reducers.
const rootReducer = combineReducers({
isMobileReducer,
imageSliderReducer
})
and now passing to store, like below:
let store = createStore(rootReducer,applyMiddleware(thunk))
and in frontend how i am accessing state
const mapStateToProps = (state) => ({
images: state.images,
isMobile: state && state.isMobile
})
imageSliderReducer.js
import {
FETCH_IMAGES_BEGIN,
FETCH_IMAGES_SUCCESS,
FETCH_IMAGES_FAILURE
} from '../actions/actionTypes'
const initialState = {
images:[],
error:null
}
const imageSliderReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_IMAGES_BEGIN:
return {...state,error:null}
case FETCH_IMAGES_SUCCESS:
return {...state,images:action.payload.images}
case FETCH_IMAGES_FAILURE:
return {...state,error:action.payload.error,images:[]}
default:
return state
}
}
export default imageSliderReducer;
isMobileReducer.js
import {
OPEN_MENU,
CLOSE_MENU,
SET_DEVICE_TYPE,
} from '../actions/actionTypes'
const initialState = {
isMenuOpen: null,
isMobile: false
}
const isMobileReducer = (state = initialState, action) => {
switch (action.type) {
case OPEN_MENU:
return {...state, isMenuOpen: true}
case CLOSE_MENU:
return {...state, isMenuOpen: false}
case SET_DEVICE_TYPE:
return {...state, isMobile: action.isMobile}
default:
return state
}
}
export default isMobileReducer;
actionCreator.js
import {
OPEN_MENU,
CLOSE_MENU,
SET_DEVICE_TYPE,
FETCH_IMAGES_BEGIN,
FETCH_IMAGES_SUCCESS,
FETCH_IMAGES_FAILURE
} from './actionTypes'
export function openMenu(isMobile) {
return {
type: OPEN_MENU
}
}
export function closeMenu(isMobile) {
return {
type: CLOSE_MENU
}
}
export function setDeviceType (isMobile) {
return {
type: SET_DEVICE_TYPE,
isMobile: isMobile
}
}
export function fetchImages() {
return dispatch => {
dispatch(fetchImagesBegin());
return fetch("https://7344.rio.com/wp-json/customapi/homeslider")
.then(handleErrors)
.then(res => res.json())
.then(json => {
dispatch(fetchImagesSuccess(json.posts));
return json.posts;
})
.catch(error => dispatch(fetchImagesFailure(error)));
};
}
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
export const fetchImagesBegin = () => ({
type: FETCH_IMAGES_BEGIN
});
export const fetchImagesSuccess = images => ({
type: FETCH_IMAGES_SUCCESS,
payload: { images }
});
export const fetchImagesFailure = error => ({
type: FETCH_IMAGES_FAILURE,
payload: { error }
});
Try using this:
const mapStateToProps = (state) => ({
images: state.imageSliderReducer.images,
isMobile: state.isMobileReducer.isMobile
})

Resources