get initialState value in reducer from action inRedux - reactjs

I am new in redux, I created a initialState in reducer.jsx like that:
const initState = {
loading: false,
todos: [],
todo: null,
};
Then in action.jsx, I want to use the value 'todo' of initState. How can I do that. I try to use useSelector but it is impossible because useSelector cannot be used in action

Try to learn redux-toolkit. It's a lot easier to learn than redux and createSlice api in redux-toolkit is what you find right now.
https://redux-toolkit.js.org/api/createslice

First of Create store using redux then install react-redux library for state management with react. follow code below step by step.
Step - 1
// redux.js
import { createStore } from 'redux';
const store = createStore(rootReducer);
export default store;
Step - 2
// rootReducer.js
import { combineReducers } from 'redux';
import todosReducer from './todosReducer';
const rootReducer = combineReducers({
todos: todosReducer,
});
export default rootReducer;
Step - 3
// todosReducer.js
const initState = {
loading: false,
todos: [],
todo: null,
};
const todosReducer = (state = initState, action) {
switch(action.type) {
case 'add_todo': {
return [
...state,
action.payload.todo
]
}
default:
return state;
}
}
Step - 4
//todosAction.js
export const addTodo = (todo) => {
return({
type:'add_todo',
payload: {
todo
}
})
};
Step - 5
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from '../store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
you can avoid file path choose yourself. import correct file path.
Step - 5
// Todos.js
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {addTodo } from './todosActions';
const Todos = () => {
const { todos } = useSelector(state => state.todos);
const dispatch = useDispatch();
useEffect(() => {
console.log("todos", todos); // show all todos state
} ,[])
const todo = {
id: 1,
title: "redux is state management library"
}
const todoHandler = () => {
dispatch( addTodo(todo));
}
return(
<div>
// Todos Here
<button onClick={todoHandler}> add todo </button>
</div>
);
}

Related

React not updating state from redux

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
};
};

Why is my reducer not triggered using redux?

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

React Redux doesn't update UI

React-Redux doesn't update UI when store changes.
I expect {this.props.isLogged} to get changed dynamically when Change button is clicked.
I searched tons of materials but I cannot find why the text doesn't change when button is clicked.
Index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { createStore } from "redux";
import reducers from "./reducers";
import { Provider } from "react-redux";
const store = createStore(
reducers);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
App.js
import React from "react";
import { connect } from "react-redux";
import { loginUser } from "./actions";
class App extends React.Component {
changeText = () => {
this.props.loginUser();
};
render() {
return (
<div>
<span>{this.props.isLogged}</span>
<button onClick={this.changeText}>Change</button>
</div>
);
}
}
const mapStateToProps = (state /*, ownProps*/) => {
return {
isLogged: state.isLogged
};
};
const mapDispatchToProps = { loginUser };
export default connect(mapStateToProps, mapDispatchToProps)(App);
./src/reducers/index.js
import { combineReducers } from "redux";
import { LOGIN_USER } from "../actions";
function userReducer(state = { isLogged: false }, action) {
switch (action.type) {
case LOGIN_USER:
return { isLogged: !state.isLogged };
default:
return state;
}
}
const reducers = combineReducers({
userReducer
});
export default reducers;
./src/actions/index.js
export const LOGIN_USER = "LOGIN_USER";
export function loginUser(text) {
return { type: LOGIN_USER };
}
Check this out..
https://codesandbox.io/s/react-redux-doesnt-update-ui-vj3eh
const reducers = combineReducers({
userReducer //It is actually userReducer: userReducer
});
As you assiging your UserReducer to userReducer prop, you will have to fetch the same way in mapStateToProps
const mapStateToProps = (state /*, ownProps*/) => {
return {
isLogged: state.userReducer.isLogged
};
};
Also, isLogged prop is a Boolean variable.. So you are gonna have to use toString().
<span>{this.props.isLogged.toString()}</span>
Since you are using combineReducers, the isLogged boolean lives in state.userReducer.isLogged.
Consider changing combineReducers to combineReducers({ user: userReducer }) and accessing the flag with state.user.isLogged.

The problem with redux not working on button click

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 };
};

redux combineReducers() is not working in my project with Ducks pattern

I want to separate modules, so I tried to separate files in the src/store/modules directory.
To merge reducer modules, I use combineReducers() in modules/index.js.
Before separating these modules, modules/index.js file's code was modules/board.js.
Then I added board.js file. I moved code of index.js to board.js. Finally I added combineReducer() in index.js, but somehow it is not working.
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './containers/App';
import store from './store';
const rootElement = document.getElementById('root');
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
rootElement
);
src/containers/BoardContainer.js
import React from 'react';
import Board from '../components/Board';
import { connect } from 'react-redux';
import * as boardActions from '../store/modules/board';
class BoardContainer extends React.Component {
componentWillMount() {
this.props.handleReadBoards();
}
render() {
/* ... */
}
}
const mapStateToProps = (state) => {
return {
boardList: state.get('boardList')
};
}
const mapDispatchToProps = (dispatch) => {
return {
handleReadBoards: () => { dispatch(boardActions.readBoardList()) }
};
}
export default connect(mapStateToProps, mapDispatchToProps)(BoardContainer);
src/store/index.js
// redux
import { createStore, applyMiddleware, compose } from 'redux';
import reducers from './modules';
// redux middleware
import thunk from 'redux-thunk';
const store = createStore(reducers,
compose(applyMiddleware(thunk))
);
export default store;
src/store/modules/index.js
import { combineReducers } from 'redux';
import board from './board';
export default combineReducers({
board
});
src/store/modules/board.js
import { createAction, handleActions } from 'redux-actions';
import { Map, List } from 'immutable';
import * as boardApi from '../../lib/api/board';
// Action Types
const READ_BOARD_LIST = 'board/READ_BOARD_LIST';
// Action Creators
export const readBoardList = () => async (dispatch) => {
try {
const boardList = await boardApi.getBoardList();
dispatch({
type: READ_BOARD_LIST,
payload: boardList
});
} catch (err) {
console.log(err);
}
}
// initial state
const initialState = Map({
boardList: List()
})
// reducer
// export default handleActions({
// [READ_BOARD_LIST]: (state, action) => {
// const boardList = state.get('boardList');
// return state.set('boardList', action.payload.data);
// },
// }, initialState);
// reducer
export default function reducer(state = initialState, action = {}) {
switch (action.type) {
case READ_BOARD_LIST:
return state.set('boardList', action.payload.data);
default:
return state;
}
}
Your reducer now contains submodules. So that you have to state from which module you want to get the data: state.board.get('boardList').
You can try to setup redux tool to easy visualize your data inside redux.
const mapStateToProps = (state) => {
return {
boardList: state.board.get('boardList')
};
}

Resources