I am learning redux. I have written an application for the same, first time. I am not able to understand why data isnt being fetched from store. Is there anything wrong with my connect call? Please help.
I am getting error that contactsList is undefined while calling map below, although connect should fetch that list as per my understanding.
ContactCards.js
import React, { Component } from 'react';
import Card from './Card';
import { connect } from 'react-redux';
const CardList = ({ contactsList }) => {
const cardsArray = contactsList.map(contact => (
<Card
key={contact.id}
name={contact.name}
email={contact.email}
phone={contact.phone}
website={contact.website}
city={contact.address.city}
companyName={contact.company.name}
id={contact.id} />
));
return (
<div className="jumbotron">
<div className='card-columns'>
{cardsArray}
</div>
</div>
);
};
const mapStateToProps = state => {
return { contactsList: state.contactsList };
};
const ContactCards = connect(mapStateToProps)(CardList);
export default ContactCards;
Reducer dataReducer
import ContactsList from '../components/MockContactsList';
import {loadContacts, updateContacts} from '../Actions/CardActions';
const INITIAL_STATE = {
contactsList: ContactsList
};
const dataReducer = (state = INITIAL_STATE, action) => {
switch(action.type) {
case loadContacts:
return state;
case updateContacts:
const updatedItems = state.contactsList.map(item => {
if(item.id === action.id){
return { ...item, ...action.payload }
}
return item
})
return updatedItems;
default:
return state;
}
};
export default dataReducer;
App.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import registerServiceWorker from './registerServiceWorker';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import reducers from './reducers/index';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
const store = createStore(reducers, {});
ReactDOM.render(
<Provider store = {store}>
<App />
</Provider>
,document.getElementById('root'));
registerServiceWorker();
Reducers index.js
import { combineReducers } from 'redux';
import dataReducer from './dataReducer';
export default combineReducers({
dataReducer
});
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import registerServiceWorker from './registerServiceWorker';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import reducers from './reducers/index';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
const store = createStore(reducers, {});
ReactDOM.render(
<Provider store = {store}>
<App />
</Provider>
,document.getElementById('root'));
registerServiceWorker();
You must first access your reducer state (dataReducer) then its property:
const mapStateToProps = state => {
return { contactsList: state.dataReducer.contactsList };
};
In your store you have a key of dataReducer:
export default combineReducers({
dataReducer
});
But you're accessing it as contactsList here:
const mapStateToProps = state => {
return { contactsList: state.contactsList };
};
So you probably need to have that key in your store instead:
export default combineReducers({
contactsList: dataReducer
});
Related
I have carefully gone through my code, nothing wrong with store, reducer function, Provider, but useSelector hook returns undefined in the App.js. Why does it return undefined?
redux.js
import {createStore} from 'redux'
const counterReducer = (state = {counter:0}, action)=>{
if(action.type ==='increment'){
return {counter:state.counter+1}
}
if(action.type ==='decrement'){
return{counter : state.counter-1}
}
}
const store = createStore(counterReducer);
export default store;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from '../src/store/redux'
import {Provider} from 'react-redux'
ReactDOM.render(
<Provider store = {store}>
<App />
</Provider>,
document.getElementById('root')
);
reportWebVitals();
App.js
import './App.css';
import {useSelector} from 'react-redux'
function App() {
const counter = useSelector(state=> state);
console.log(counter) //undefined
return (
<div></div>
);
}
export default App;
redux.js
import { createStore } from 'redux';
const counterReducer = (state = { counter: 0 }, action) => {
**// Updated previous if statement using switch statement**
switch (action.type) {
case 'increment':
return { ...state, counter: state.counter + 1 };
case 'decrement':
return { ...state, counter: state.counter - 1 };
default:
return { counter: 0 }; // you need to define a default value;
}
const store = createStore(counterReducer);
export default store;
app.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import './style.css';
export default function App() {
const counter = useSelector((state) => state.counter);
const dispatch = useDispatch();
console.log(counter);
return (
<div>
<h1>{counter}</h1>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
}
Look at this code, we always need a default value when creating reducer. Using switch statement for this case I think safe.
you can see this solution: stackbllitz
Hi guys i was setting up redux in my react native project but facing some issues while setup even though i am pretty sure i haven't used getState till now but as ssons as app runs i get error
TypeError: store.getState is not a function. (In 'store.getState()',
'store.getState' is undefined)
my code is as
reducers / hireducer.js
import { HI } from "../constants";
const initialState = {
count: 0,
};
const countReducer = (state = initialState, action) => {
switch (action.type) {
case HI:
return {
...state,
count: action.payload,
};
default:
return state;
}
};
export default countReducer;
reducers / index.js
import { combineReducers } from "redux";
import hiReducer from "./hireducer.js";
export default combineReducers({
hi: hiReducer,
});
store / configStore
import { createStore } from "redux";
import reducers from "../reducers/index";
const configureStore = () => {
return createStore(reducers);
};
export default configureStore;
App.js
import "react-native-gesture-handler";
import React from "react";
import { NavigationContainer } from "#react-navigation/native";
import AuthNavigator from "./navigations/AuthNavigation";
import { withHOC } from "./index.js";
function App() {
return (
<NavigationContainer>
<AuthNavigator />
</NavigationContainer>
);
}
export default withHOC(App);
index.js
import React from "react";
import { Provider } from "react-redux";
import configStore from "./redux/store/configStore";
export const withHOC = (App) => (props) => {
return (
<Provider store={configStore}>
<App {...props} />
</Provider>
);
};
even though if i normally wrap in without providing store i still get the same error
Your configStore returns a function instead of a store object.
So you rather call the function in your app like
<Provider store={configStore()}>
<App {...props} />
</Provider>
Or you create a store object from configStore like
const configureStore = () => {
return createStore(reducers);
};
export default configureStore();
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)
Redux is throwing me:
Error: Expected the reducer to be a function.
at lines
from index:
const { store } = configureStore();
from configureStore:
const store = createStore(rootReducer, initialState, devToolsEnhancer())
index.js
import React from 'react';
import { render } from 'react-dom';
import Root from './Root';
import './index.css';
import App from './whitesheet-components/App';
import registerServiceWorker from './registerServiceWorker';
import configureStore from './store/configureStore';
const { store } = configureStore();
const MOUNT_NODE = document.getElementById('root');
const load = Component =>
render(
<App>
<Component store={store} />
</App>,
MOUNT_NODE,
);
load(Root);
registerServiceWorker();
configureStore.js
import { createStore } from 'redux';
import { devToolsEnhancer } from 'redux-devtools-extension';
import rootReducer from './rootReducer';
const isDevelopment = process.env.NODE_ENV !== 'production';
export default function configureStore(initialState = {}) {
const store = createStore(rootReducer, initialState, devToolsEnhancer());
if (isDevelopment && module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('./rootReducer.js', () => {
const nextReducer = require('./rootReducer').default; // eslint-disable-line global-require
store.replaceReducer(nextReducer);
});
}
return { store };
}
rootReducer
import mockReducer from './mockReducer';
export default { mockReducer };
mockReducer
export default function reducer(state = { hola: 'as' }, { type }) {
switch (type) {
default:
return state;
}
}
Can't find the bug. First time creating a redux store with devtools plugin support by myself
It looks like you're exporting an object instead of a function in your root reducer.
rootReducer
import mockReducer from './mockReducer';
// export default { mockReducer };
export default mockReducer;
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 };
};