I have a functional counter app I'm working on with react-redux. I can see every time that I dispatch an action using my Increment/Decrement functions the state updates, however, I am unable to actually output the value of my state.
This is my first time trying to build a redux application with modules(as opposed to building an html file with a redux cdn). Please help me figure out what I'm doing wrong.
Thanks.
//App.js
import { Increment, Decrement } from './redux'
class App extends Component {
render() {
return (
<div className="App">
<h1>{this.props.count}</h1> //Doesn't output anything
<button onClick={this.props.Increment}>+</button>
<button onClick={this.props.Decrement}>-</button>
</div>
);
}
}
const mapStateToProps = state => ({
count: state.count
})
const mapDispatchToProps = {
Increment,
Decrement
}
const AppContainer = connect(
mapStateToProps,
mapDispatchToProps
)(App)
export default AppContainer
//redux.js
import { createStore } from 'redux';
export const Increment = () => {
return {
type: 'INCREMENT'
}
}
export const Decrement = () => {
return {
type: 'DECREMENT'
}
}
export const reducer = (state = 0, action) => {
switch(action.type){
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
export function configureStore(intitalState = 0){
const store = createStore(reducer, intitalState)
return store;
}
export const store = configureStore()
//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { Provider } from 'react-redux';
import { store } from './redux';
import AppContainer from './App';
ReactDOM.render
(<Provider store={store}>
<AppContainer/>
</Provider>, document.getElementById('root'));
In this case state is actually a value, not an object that stores value as count property.
It should be either:
const mapStateToProps = state => ({
count: state
})
Or combineReducers can be used to map specific reducer as store property:
const store = createStore(combineReducers({count: reducer }), intitalState)
Related
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();
I'm trying to add redux to my react app.
My index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, compose, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import dashboardReducer from './store/reducer/dashboard';
const rootReducer = combineReducers({
dashboard: dashboardReducer
});
const store = createStore(rootReducer);
const app = (
<Provider store={store}>
<App />
</Provider>
)
ReactDOM.render(
<React.StrictMode>
{app}
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
Then, I have a store folder with actions folder and reducer folder.
In my actions folder, I have the actionsType.js:
export const TEST = 'TEST';
I also have the dashboard.js:
import * as actionTypes from './actionsTypes';
export const test = () => {
return {
type: actionTypes.TEST
}
};
And finally, the index.js to return the actions:
export {
test
} from './dashboard';
Inside the reducer folder, I just have one reducer now, called dashboard.js
import * as actionTypes from '../actions/actionsTypes';
const initialState = {
counter: 0
}
const reducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.TEST:
return {
...state,
counter: state.counter++
};
default:
return state;
}
};
export default reducer;
I create, in my components folder, a test class Dashboard.js to test my redux.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as action from '../store/actions/index';
class Dashboard extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0
};
}
render() {
return (
<div>
<h2>Main Page: {this.props.ctr}</h2>
<button onClick={this.props.onTest}>TEST</button>
</div>
);
}
}
const mapStateToProps = state => {
return {
ctr: state.counter
};
};
const mapDispatchToProps = dispatch => {
return {
onTest: () => dispatch(action.test())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);
When I open the page, it just say "Main Page: ". Shouldn't it start with a 0 value? Also, When I click on the button "test", nothing changes.
Sorry, I'm just starting with react and redux, I'm probably missing a lot of configuration.
Thanks
You're not getting the value from the correct reducer. A nice way to debug that is logging the state inside the mapping:
const mapStateToProps = state => {
console.log(state); // This will run with EVERY state change
return {
ctr: state.counter
};
};
Since you named your reducer as dashboard, just call it there:
const mapStateToProps = state => {
return {
ctr: state.dashboard.counter
};
};
Try this:
BEFORE
const mapStateToProps = state => {
return {
ctr: state.counter
};
};
AFTER
const mapStateToProps = state => {
return {
ctr: state.dashboard.counter
};
};
I am new to Redux and was learning how to use it with React. Basically, I did everything correctlyin terms of setting up Redux with react app but when I click on button increment I expect displaying counter to increment by one. But when I do that nothing happens and, certainly, I have checked dispatch and action being sent but basically all is ok. Thus I truly need your help guys here is the code I am using:
index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import registerServiceWorker from "./registerServiceWorker";
import { createStore } from "redux";
import reducer from "./store/reducer";
import { Provider } from "react-redux";
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
registerServiceWorker();
reducer.js
const initialState = {
counter: 0
};
const reducer = (state = initialState, action) => {
if (action.type === "INCREMENT") {
return { counter: state.counter + 1 };
}
return state;
};
export default reducer;
counter.js
import React, { Component } from "react";
import { connect } from "react-redux";
import CounterControl from "../../components/CounterControl/CounterControl";
import CounterOutput from "../../components/CounterOutput/CounterOutput";
class Counter extends Component {
render() {
return (
<div>
<CounterOutput value={this.props.ctr} />
<CounterControl
label="Increment"
clicked={() => this.props.onIncrement}
/>
</div>
);
}
}
const mapStateToProps = state => {
return { ctr: state.counter };
};
const mapDispatchToProps = dispatch => {
return {
onIncrement: () => dispatch({ type: "INCREMENT" })
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(Counter);
Did you register your reducer with store?
If not, please do that.
I believe this thing should not return string:
const mapStateToProps = state => {
return { ctr: state.counter };
};
I am trying to create something similar to todo app with react and redux from here.I have been reading all the solutions for this problem and nothing seems to be working for my case.
Most of the solutions purpose using Provider which I am already using. Any help is much appreciated.
Edit - Few import statement might be missing in snippets, but all components are being imported whenever needed and actions are also defined in action file.
Index.js
import App from './components/App'
import reducer from './reducers/index'
const store = createStore(reducer)
const AppWithStore = (
<Provider store={store}>
<App />
</Provider>
)
ReactDOM.render(AppWithStore, document.getElementById('root'))
Update - Combined Reducer code
import React from 'react'
import { combineReducers } from 'redux'
import TestReducer from './TestReducer'
export default combineReducers({
TestReducer,
})
App.js
import Test from './Test';
class App extends Component {
render() {
return (
<Test />
);}
}
ReactDOM.render(
(<App/>),
document.getElementById("root")
);
export default App
Test.js contains both component and container
import { connect } from 'react-redux'
import { add } from '../actions'
const mapStateToProps = state => ({
todos: state.todos,
})
class Test extends Component {
dosomething() {
const dispatch = this.props;
dispatch(add("New Note"));
}
render() {
return (
<div>
< button OnClick = { this.dosomething.bind(this)} > Test </button>
</div>
)
}
}
export default connect(mapStateToProps)(Test)
The reducer logic for Test is as given below
import React from 'react';
const TestReducer = (state = [], action) => {
const todos = state;
const {type, payload} = action;
switch(action.type){
case 'ADD': {
return {
...state,
todos:"new todo"
}
}
}
return state;
}
export default TestReducer
You should remove
ReactDOM.render(
(<App/>),
document.getElementById("root")
); from App.js file
When you call it again in App.js a new component instance independent of others is created, That's why it is not finding store.As store is not passed to it.
You can check it here https://codesandbox.io/s/vy7wwqw570. As i had remove render api call from app.js it is working now.
you need to import your reducers so that you
if your file name is TestReducer.js
import React from 'react';
export const TestReducer = (state = [], action) => {
const todos = state;
const {type, payload} = action;
switch(action.type){
case 'ADD': {
return {
...state,
todos:"new todo"
}
}
}
return state;
}
then import it in this manner
import {TestReducer} from './TestReducer.js';
const store = createStore(TestReducer);
Try replacing todos: state.todos with todos: state.TestReducer.todos
import { connect } from 'react-redux'
import { add } from '../actions'
const mapStateToProps = state => ({
//todos: state.todos,
todos: state.TestReducer.todos
})
class Test extends Component {
dosomething() {
const dispatch = this.props;
dispatch(add("New Note"));
}
render() {
return (
<div>
< button OnClick = { this.dosomething.bind(this)} > Test </button>
</div>
)
}
}
export default connect(mapStateToProps)(Test)
I'm trying hard to wire redux store in a react-native app but seems like I'm missing something. Any help will be appreciated.
action.js
export const getdata = (data) => {
return (dispatch, getState) => {
dispatch({
type: "GET_DATA",
data
});
};
};
reducer/dataReducer.js
export default (state = {}, action) => {
switch (action.type) {
case GET_DATA:
return { ...state, response: action.data };
default:
return state;
}
};
reducer/index.js
import { combineReducers } from 'redux';
import dataReducer from './dataReducer';
//other imports
export default combineReducers({
data: dataReducer,
//other reducers
});
store/configureStore.js
import { createStore, compose, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducers from './../reducer;
export default function configure(initialState = {}) {
const store = createStore(reducer, initialState, compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : f => f
));
return store;
}
main.js (where I dispatch action)
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import Routes from './Routes';
import configureStore from './store/configureStore';
import { getdata} from './actions';
const store = configureStore();
store.subscribe(() => {
console.log('New state', store.getState); //doesn't update at all
});
class Main extends Component {
componentDidMount() {
store.dispatch(getdata('abc')); //calling action creator
}
render() {
return (
<Provider store={store}>
<Routes />
</Provider>
);
}
}
export default Main;
I also tried wiring Chrome extension to see redux store updates, but no luck there. It always says no store found. How can I get this working?
store can be accessed in the a child class inside the Routes Component by react-redux connect
but here no store in the class but I think You can do the following
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import Routes from './Routes';
import configureStore from './store/configureStore';
import { getdata} from './actions';
const store = configureStore();
store.subscribe(() => {
console.log('New state', store.getState()); //getState() is method
});
store.dispatch(getdata('abc'));
class Main extends Component {
render() {
return (
<Provider store={store}>
<Routes />
</Provider>
);
}
}
export default Main;
You want to dispatch your actions from your container components (aka. smart components, the ones connected to the Redux store). The container components can define props in mapDispatchToProps that let them dispatch actions. I don't have your code, so I'm just gonna assume that your Routes component is the container component that you are connecting to the Redux store. Try something like:
class Routes extends Component {
....
componentDidMount() {
this.props.retrieveData();
}
...
}
const mapStateToProps = state => {
...
};
const mapDispatchToProps = dispatch => {
return {
retrieveData: () => dispatch(getdata('abc'));
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Routes);