following is the code that i used in order to manage the state but unfortunately my state is not updating when using redux
the action is as given below:
export let incNumber = ()=>{
return {
type: 'INCREMENT'
}
}
export let decNumber = ()=>{
return {
type: 'DECREMENT'
}
}
while the reducer is as given below:
import mainReducer from "./reducers";
import { createStore } from "redux";
const store = createStore(mainReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
export default store;
the main app.js file is as given below:
import './App.css';
import {useSelector, useDispatch} from 'react-redux';
import {incNumber, decNumber} from './actions/index';
function App() {
let myState = useSelector((state)=> {
return state.changeTheNumber;
});
console.log(myState);
const dispatch = useDispatch();
return (
<>
<div className="main-div">
<div className="container">
<h1>Increment/Decrement counter</h1>
<h4>using React and Redux</h4>
<div className="quantity">
<a className="quantity__minus" title="Decrement" onClick={()=>dispatch(decNumber())}><span>-</span></a>
<input name="quantity" type="text" className="quantity__input" defaultValue={myState}/>
<h1>{myState}</h1>
<a className="quantity__plus" title="Increment" onClick={()=>dispatch(incNumber())}><span>+</span></a>
</div>
</div>
</div>
</>
);
}
export default App;
the code of mainReducer is:
import {combineReducers} from 'redux';
import changeTheNumber from "./upDown";
const mainReducer = combineReducers({
changeTheNumber
})
export default mainReducer;
updown reducer is given as:
const initialState = 0;
const changeTheNumber = (state = initialState, action) => {
switch (action.type) {
case "INCREMENT": return state + 1;
case "DECREMENT": return state - 1;
default: return state;
}
}
export default changeTheNumber;
now the problem is that although as soon as i click on + button, the updated value is being shown on console in the browser but is not updated in the field specified. Any solutions?
Related
I have started learning react-redux and was trying out the same but somehow the props are getting returned as undefined after mapping. Sharing code flow:
Below is the detailed code giving a brief idea on each component used.
App.js:
import './App.css';
import CakeContainer from './redux/cakes/CakeContainer';
import React from 'react';
import { Provider } from 'react-redux';
import store from './redux/store';
function App() {
console.log(store.getState())
return (
<Provider store = {store}>
<div className="App">
<CakeContainer/>
</div>
</Provider>
);
}
export default App;
CakeContainer.js
import React from 'react'
import { connect } from 'react-redux'
import { buyCake } from './CakeAction'
function CakeContainer(props) {
return (
<div>
<h1>Cake Container !!</h1>
<h2>Number of cakes - {props.cake}</h2>
<button onClick = {props.buyCake}> buy cakes</button>
</div>
)
}
const mapStateToProps = (state) =>{
return {
cake: state.cakeQuant
}
}
const mapDispatchToProps = dispatch => {
return {
buyCake: () => dispatch(buyCake())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(CakeContainer)
Action.js
import {BUY_CAKE} from './CakeTypes'
export const buyCake = () =>{
return{
type: 'BUY_CAKE'
}
}
Reducer:
Reducer where i am passing the initial state and action for further processing.
import { BUY_CAKE } from "./CakeTypes";
const initialState = {
cakeQunt : 10
}
const CakeReducer = (state = initialState, action)=>{
switch(action.type){
case 'BUY_CAKE': return {
...state,
cakeQunt: state.cakeQunt - 1
}
default: return state;
}
}
export default CakeReducer;
Store.js
Creating store and passing reducer details to it
[![import { createStore } from "redux";
import CakeReducer from './cakes/CakeReducer'
const store = createStore(CakeReducer,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())
console.log(store.getState())
export default store;][1]][1]
Image showing the props value as undefined:
[1]: https://i.stack.imgur.com/EjXU1.png
I am trying to make a simple exercise for react-redux to understand the process but somehow I am stuck .. any help would be really appreciate.
The interesting part is when I do subscribe and try to log store into the console, it works and shows me updated value but I am not able to select it using useSelector
Also with the help of Dev tool's i could see the state being changed from INIT to ADD_USER..
Below are my components files and reducers.
App.js
import React from "react";
import { Provider } from "react-redux";
import store from "./stores/store";
import { HomePage } from "./components/containers/HomePage";
function App() {
return (
<Provider store={ store }>
<HomePage/>
</Provider>
);
}
export default App;
HomePage.js. --> Here state.isLogin is not selected.. but the subscribe comment works
import React from "react";
import { Sidebar } from "./Sidebar";
import { LoginPage } from "./LoginPage";
import { useSelector } from "react-redux";
export const HomePage = () => {
const userLogin = useSelector(state => state.isLogin);
// const storeState = store.subscribe (() => console.log(store.getState()));
return (
<div>
<LoginPage />
<Sidebar />
</div>
);
};
LoginPage.js
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import * as action from "../../action/index";
export const LoginPage = (setLogin) => {
const dispatch = useDispatch();
const [name, setName] = useState("");
const createUser = (e) => {
e.preventDefault();
const addUser = {
name: name,
isLogin: true
};
dispatch(action.addUsers(addUser));
};
return (
<div className="card border-0 shadow">
<div className="card-header">Login Here!</div>
<div className="card-body">
<form onSubmit={(e) => createUser(e)}>
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="Enter Your Name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
<button className="btn btn-primary" type="submit">
Create Contact
</button>
</form>
</div>
</div>
);
};
reducers - Index.js and user.js
import userReducer from './users'
import { combineReducers} from "redux";
const allReducers = combineReducers({
addUser : userReducer,
});
export default allReducers;
User.js
import * as types from '../actionTypes/index'
const intialState = {
user: [],
messages : [],
isLogin : false
};
const users = (state = intialState, action) => {
switch (action.type) {
case types.ADD_USER:
return {
...state,
user: [action.payload.name, ...state.user],
isLogin: action.payload.isLogin
};
default:
return state
}
}
export default users;
Store.js
import { createStore } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import allReducers from '../reducers'
const store = createStore(allReducers,composeWithDevTools());
export default store;
Any idea's/Input on what went wrong ? or what is the issue?
Thank you
Try using below code in HomePage
const userLogin = useSelector(state => state.addUser.isLogin);
i am learning redux with react and trying to create an app where i have a range-slider, whose value dictates how many Box components will be rendered on the screen.
i am trying to make the range-slider a controlled component but can't make it change the store. i am getting no errors.
the component:
import React from 'react';
import { connect } from 'react-redux';
import { setBoxNumber } from '../actions/actions';
const Slider = ({ boxNumber, handleChange }) => {
return(
<div>
<div>
{boxNumber}
</div>
<div>
<input
onChange={handleChange}
value={boxNumber}
type="range"
min="12"
max="480"
/>
</div>
</div>
)
}
const mapStateToProps = (state) => {
return { boxNumber: state.boxNumber }
}
const mapDispatchToProps = (dispatch) => {
return {
handleChange: (event) => dispatch(setBoxNumber(event.target.value))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Slider);
the reducer:
import { combineReducers } from 'redux';
export const boxNumberReducer = (boxNumber = 40, action) => {
switch(action.payload) {
case 'SET_BOX_NUMBER':
return action.payload;
default:
return boxNumber;
}
}
export default combineReducers({
boxNumber: boxNumberReducer
})
the action:
export const setBoxNumber = (number) => {
return {
type: 'SET_BOX_NUMBER',
payload: number
}
}
i also tried to call the handleChange method with an arrow function on change, like i would do with a controlled react component without redux, but it's making no difference
I think your reducer is configured incorrectly. You can pass all the initial states inside the variable initialState like this.
//reducer.js
import { combineReducers } from "redux";
const initialState = {
boxNumber: 40,
};
const boxReducer = (state = initialState, action) => {
switch (action.type) {
case "SET_BOX_NUMBER":
return {
...state,
boxNumber: action.payload,
};
default:
return state;
}
};
export default combineReducers({
boxReducer,
});
This is how your index.js file should look like:
//index.js
import React from "react";
import ReactDOM from "react-dom";
import Slider from "./Slider.js";
import { Provider } from "react-redux";
import { createStore } from "redux";
import reducer from "./redux/reducer";
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<Slider />
</Provider>,
document.getElementById("root")
);
You need to update your mapStateToProps in Slider.js to access the states in your reducer.
//Slider.js
const mapStateToProps = (state) => {
return { boxNumber: state.boxReducer.boxNumber };
};
This is a simple fix. As your app gets bigger, you'll need more reducers and thus it's better to keep a separate file for that.
Need some help.
As I am trying to get some understanding of React/REdux global state I made some simple get request.
This is done with Axios, thunk, Redux, but i can't get this working
I have Post.js file, nothing fancy
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import PostForm from './PostForm';
export class Post extends Component {
static propTypes = {
posts: PropTypes.any,
fetchPosts: PropTypes.func,
};
componentDidMount() {
const { fetchPosts } = this.props;
fetchPosts();
}
render() {
const { posts } = this.props;
return (
<div>
<PostForm addPost={this.onSubmit} />
<br />
<div>
{posts.map(post => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</div>
))}
</div>
</div>
);
}
}
export default Post;
Next i have my PostContainer.js
import { connect } from 'react-redux';
import Post from './Post';
import { fetchFromApi } from '../reducers/postReducers';
const mapStateToProps = state => ({
posts: state.posts,
});
const mapDispatchToProps = dispatch => ({
fetchPosts: () => dispatch(fetchFromApi()),
});
export default connect(mapStateToProps, mapDispatchToProps)(Post);
My reducer
import Axios from 'axios';
/* action type */
const FETCH_POSTS = 'FETCH_POSTS';
/* action creator */
export const fetchStarted = payload => ({ payload, type: FETCH_POSTS });
/* thunk */
export const fetchFromApi = () => {
return (dispatch, getState) => {
Axios.get('https://jsonplaceholder.typicode.com/posts?_limit=5').then(res =>
dispatch(fetchStarted(res.data))
);
};
};
/* reducer */
export default function reducer(state = [], action = {}) {
switch (action.type) {
case FETCH_POSTS: {
return {
...state,
data: action.payload,
};
}
default:
return state;
}
}
and my store
import { combineReducers, applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
import postReducer from './reducers/postReducers';
const initialState = {
posts: {
data: {},
},
};
const reducers = {
posts: postReducer,
};
Object.keys(initialState).forEach(item => {
if (typeof reducers[item] == 'undefined') {
reducers[item] = (state = null) => state;
}
});
const combinedReducers = combineReducers(reducers);
const store = createStore(
combinedReducers,
initialState,
composeWithDevTools(applyMiddleware(thunk))
);
export default store;
All of that is doing not much. My map method is trying to map empty posts object. And for some reason my fetchPosts is not dispatched. I have reade some old posts here but still can't get this working
Thanks
Edit
this is my app.js file with container
import React from 'react';
import './App.css';
import Post from './components/PostContainer';
import { Provider } from 'react-redux';
import store from './store';
function App() {
return (
<Provider store={store}>
<div className='App'>
<Post />
</div>
</Provider>
);
}
export default App;
I managed to get this working.
Data was not there when my posts array was render. After passing simple if statemante all is working
Sory for my English!
I am doing test work on React.js. The task is to make a regular blog. I ran into an unwanted problem. As a rule, componentDidMount makes entries, ready data and is called once.
I invoke the loadPosts action in the CDM to get the data.
The takeEvery effect sees the necessary saga, but does not cause it, but skips it.
When I press a button, everything works fine.
I'm new to React. All i tried is google
repository with project
branch - dev-fullapp
index.js
import store from "./redux/store";
const app = (
<BrowserRouter>
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>
);
store.js
import { createStore, compose, applyMiddleware } from "redux";
import createSagaMiddleware from "redux-saga";
import apiSaga from "./sagas/index";
import rootReducer from "./reducers/index";
const initialiseSagaMiddleware = createSagaMiddleware();
const storeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
rootReducer,
storeEnhancers(applyMiddleware(initialiseSagaMiddleware))
);
initialiseSagaMiddleware.run(apiSaga);
export default store;
sagas.js
import { put, call, takeEvery } from "redux-saga/effects";
import { fetchGetPosts } from "../apis/index";
import { setErrorPosts, setPosts } from "../actions/actions-posts";
function* workerGetPosts() {
try {
const posts = yield call(fetchGetPosts);
yield put(setPosts(posts));
} catch (err) {
yield put(setErrorPosts(err));
}
}
export default function* watchSaga() {
yield takeEvery(POSTS.LOADING, workerGetPosts);
}
actions.js
import { POSTS } from "../constants";
export const loadPosts = () => {
console.log('action-load')
return {
type: POSTS.LOADING
}
};
export const setPosts = payload => ({
type: POSTS.LOAD_SUCCESS,
payload
});
export const setErrorPosts = error => ({
type: POSTS.ERROR,
error
});
rootReducer.js
import { combineReducers } from "redux";
import postsReducer from "./reducer-posts";
import loadReducer from "./reducer-load";
const rootReducer = combineReducers({
posts: postsReducer,
isLoad: loadReducer
});
export default rootReducer;
reducer-posts.js
import { POSTS } from "../constants";
const postState = {
posts: []
};
function postsReducer(state = postState, action) {
switch (action.type) {
case POSTS.LOAD_SUCCESS:
return {
...state,
posts: [...action.payload]
};
default:
return state;
}
}
export default postsReducer;
reducer-load.js
import { POSTS } from "../constants";
import { combineReducers } from "redux";
const loadReducerPosts = (state = false, action) => {
switch (action.type) {
case POSTS.LOADING: return false;
case POSTS.LOAD_SUCCESS: return true;
case POSTS.ERROR: return false;
default: return state;
}
};
const loadReducer = combineReducers({
isLoadPost: loadReducerPosts,
});
export default loadReducer;
news.jsx
class News extends Component {
componentDidMount() {
loadPosts();
}
render() {
CONST { loadPosts }this.props
return (
<main>
// code
<button onClick={loadPosts}>Test Button</button>
</main>
);
}
}
const mapStateToProps = (
{ posts: { loading, posts, success } }
) => ({
posts,
loading,
success
});
export default connect(
mapStateToProps,
{ loadPosts }
)(News);
loadPosts method is available as props to the React component in current case. Unlike in componentDidMount, on button click you are calling the function from props. You have to use this.props.loadPosts() on both places