I have two actions one that will close my menu (would be false) and one that will open the menu (would be true) in my reducer I set the initial value to true
import { OPENED_MENU,CLOSED_MENU } from './types';
export const OpenMenu = status => ({
type:OPENED_MENU,
status
});
export const CloseMenu = status => ({
type:CLOSED_MENU,
status
});
reducer:
import { OPENED_MENU, CLOSED_MENU } from '../../actions/menu/types';
const initialState = {
status: true,
};
const CheckingStatus = ( state = initialState, action) => {
switch (action.type){
case OPENED_MENU:
return{
}
case CLOSED_MENU:
return{
}
default:
return state;
}
}
export default CheckingStatus;
I would like to know how I return in my action a false or true boolean value.
or how it could improve my logic.
You can try the following code:
import {TOGGLE_MENU } from '../../actions/menu/types';
const initialState = {
menuStatus: true,
};
const CheckingStatus = ( state = initialState, action) => {
switch (action.type){
case TOGGLE_MENU:
return{
...state,
menuStatus: !state.menuStatus
}
default:
return state;
}
}
export default CheckingStatus;
Why won't you toggle the menu value, you just create one action and use it to open and close.
On the reducer you toggle the prevState
Related
I am using useDispatch two times to change my todos and then change my login status. Both work seperately but when put after each other the second dispatch overwrites my list of todos to an empty object [].
How would I make this work?
Axios Post
axios
.post("http://localhost:3333/user/login", newUser)
.then((response) => {
//do stuff
dispatch(changeTodos(stuff));
dispatch(login());
});
Actions
export const login = (data) => {
return {
type: "LOGIN",
data: data,
};
};
export const changeTodos = (data) => {
return {
type: "CHANGETODOS",
data: data,
};
};
Reducer
const loggedReducer = (state = false, action) => {
switch (action.type) {
case "LOGIN":
return true;
case "LOGOUT":
return false;
default:
return false;
}
};
export default loggedReducer;
const todosReducer = (state = [], action) => {
switch (action.type) {
case "CHANGETODOS":
return action.data;
default:
return [];
}
};
export default todosReducer;
For your default you need to return state otherwise it's gonna hit the default when it doesn't match the action type. For example, LOGIN is will make your TodosReducer return [] which is why it's being cleared out.
default:
return state;
I am having a code that looks like this
reducer
const initState = { isLoggedIn: false };
const isLoggedInReducer = (state = initState, action) => {
switch (action.type) {
case "LOG_IN":
return { isLoggedIn: true };
case "LOG_OUT":
return { isLoggedIn: false };
default:
return {isLoggedIn:false};
}
};
export default isLoggedInReducer;
action
export const logIn = () => {
return {
type:'LOG_IN'
}
}
export const logOut = () => {
return {
type:'LOG_OUT'
}
}
screen
import React from 'react'
import {useDispatch,useSelector} from 'react-redux'
import {logIn , logOut} from '../redux/actions/isLoggedInAction'
const AuthScreen = () => {
console.log('auth page re-rendered')
let status = useSelector(state => state.isLoggedIn)
console.log(status)
const dispatch = useDispatch()
return <>
<h1> auth is {status} status</h1>
<button onClick={()=>dispatch(logIn())}>authenticate me</button>
<button onClick={()=>dispatch(logOut())}>un auth me</button>
</>
}
export default AuthScreen
The problem is, something causes the app to render twice, and update the store
The variable should not have changed unless I dispatch an action, which I clearly did not. Also the value of the variable is logged out but doesnt print inside the h1 tag.
If I change the default case of the reducer to something like
const initState = { isLoggedIn: false };
const isLoggedInReducer = (state = initState, action) => {
switch (action.type) {
case "LOG_IN":
return { isLoggedIn: true };
case "LOG_OUT":
return { isLoggedIn: false };
default:
return {isLoggedIn:' hello world'};
}
};
export default isLoggedInReducer;
Then I get this output
The above output suggests that the default case was somehow run. But again, I did not dispatch any action to it. I am only reading the data using the "useSelect" but something is dispatching actions that I dont know about.
I am very new to redux and trying to learn. Thanks for your time.
In your default case, return the state as is:
default:
return state;
If you return a new object, React will treat the state as having changed and rerender the component, as equality is checked by ref by default.
How do I get the state of this? I only need to put it as false and true the time I want at my components, but i`m doing something wrong, i know how do it when calling an API, but not like this.
I have this actions:
import { HIDE_MENU, ESTADO_MENU } from "./types";
export const hideMenu = dispatch => {
return dispatch({
type: HIDE_MENU
});
};
export const estadoDoMenu = open => dispatch => {
dispatch({
type: ESTADO_MENU
});
};
and this reducer:
import { HIDE_MENU, ESTADO_MENU } from "../actions/types";
const initialState = {
open: true
};
export default function(state = initialState, action) {
switch (action.type) {
case HIDE_MENU:
return {
...state,
open: false
};
case ESTADO_MENU:
console.log("chega aqui");
return {
...state
};
default:
return state;
}
}
but calling it like this:
componentDidMount() {
console.log("Estado do Menu: ", this.props.estadoDoMenu());
}
I get undefined at the console, what is wrong?
I'm pretty new in react so this might be a silly question.
I'm working on an app that manage rss feeds, so the structure of my entire app is similar to this one
<div className="App">
<Header />
<Feeds />
</div>
both components have their own reducer and actions.
the problem appears when I'm trying to create a new feed (actually managed in the feeds reducer) from my header component. so I have to access to the state of the feedsReducer from my headerReducer.
I'm not sure how to proceed at this point.
should I access the feeds reducer from the header component? ( this also implies that the feedsReducer needs to know my header actions)
I'll add some code to make the problem clear
index.js
import feedsReducer from './components/Feeds/FeedsReducer';
import headerReducer from './components/Header/HeaderReducer';
const rootReducer = {
feeds:feedsReducer,
header: headerReducer
};
const store = createStore(combineReducers(rootReducer));
Header/Header.js
import { ADD_FEED } from './actions';
class Header extends Component {
state = {
feedUrl: ""
};
addFeed = () => {
axios.post(
'/feeds/add',
{
url: 'myNewRssFeed.com'
})
.then(feed => {
//this is calling the HeaderReducer
this.props.addFeed(feed.data);
})
.catch(err => console.log(err));
}
}
const mapDispatchToProps = dispatch => {
return {
addFeed: (feed) => dispatch({ type: ADD_FEED, payload: { feed } })
};
};
export default connect(null, mapDispatchToProps)(Header);
Header/actions.js
export const ADD_FEED = "ADD_FEED";
HeaderComponent/HeaderReducer.js
const reducer = (state, action) => {
const newState = {
...state
}
switch (action.type) {
case storeActions.ADD_FEED:
// at this point newState.feeds doesn't exist because it's part from the FeedsReducer
newState.feeds = newState.feeds.push(action.payload.feed);
break;
}
return newState;
}
Feeds/FeedsReducer.js
const initialState = {
feeds: []
}
const reducer = (state = initialState, action) => {
const newState = {
...state
}
switch (action.type) {
//this action is commented because was recently moved to the headerComponent/actions.js
/* case storeActions.ADD_FEED:
newState.feeds = newState.feeds.push(action.payload.feed);
break; */
case storeActions.LOAD_FEEDS:
newState.feeds = action.payload.feeds;
break;
}
return newState;
}
Thanks in advice.
I don't really think you need to access reducer in any way. Reducer function will update store based on action it's listenning to.
Here is an example:
import * as constants from 'constantpathhere';
export function feedReducer(state = INITIAL_STATE, action) {
const { type, payload } = action;
switch(type) {
case constants.ADD_FEED: // listen to ADD_FEED action
return {... state, data: payload };
case constants.LOAD_FEEDS: // listen to LOAD_FEEDS
return {...state, loading: true }
...
default:
return state;
}
}
export function headReducer(state = INITIAL_STATE, action) {
const { type, payload } = action;
switch(type) {
case constants.ANY_ACTION: // listen to ADD_FEED action
return {... state, data: payload };
case constants.ANY_OTHER_ACTION_LOADING: // listen to LOAD_FEEDS
return {...state, loading: true }
...
default:
return state;
}
}
//ACTIONS
export function loadFeeds() {
return {
type: constants.LOAD_FEEDS
}
}
export function addFeed(payload) {
return {
type: constants.ADD_FEED,
payload
}
}
export function triggerAnyAction(payload) {
return {
type: constants.ANY_ACTION,
payload
}
}
These actions above may be dispatched from any component, be it Header or Feeds, only reducer(s) listening to that particular action will update the store.
Briefly, you only need to know which action to dispatch where and only reducer listing to that action will do whatever you instructed it to do
When triggering an action updateLog, it seems it resets other state items. In my case updateLog should manipulate log and that works just fine. The thing is it also resets tasks to the default values. What am I doing wrong here?
Component:
class Generator extends Component {
render() {
return (
<div className="generator">
<Inputs />
<button onClick={this.generate.bind(this)}>Go!</button>
<Log />
</div>
);
}
generate() {
this.props.updateLog("ANYTHING!");
}
}
function mapStateToProps(state) {
return {
tasks: state.tasks
};
}
function matchDispatchToProps(dispatch){
return bindActionCreators({updateLog: updateLog}, dispatch);
}
export default connect(mapStateToProps, matchDispatchToProps)(Generator);
Action:
export const updateLog = (message) => {
return {
type: 'LOG_UPDATED',
payload: message
}
};
Logreducer:
const initialLog = "";
export default function (state = initialLog, action) {
switch (action.type) {
case 'LOG_UPDATED':
return state + "\n" + action.payload
break;
}
return state;
}
All reducers:
const allReducers = combineReducers({
tasks: taskReducer,
log: logReducer
});
export default allReducers
taskReducer:
export default function (state = null, action) {
switch (action.type) {
case 'TASK_UPDATED':
var tasks = Object.assign({}, action.payload);
return tasks;
break;
}
// Default task properties
return {
CreateDatabaseTask: {
enabled: false,
type: "sqlite"
}
}
}
The problem lies in your task reducer. If the action type matches none of the ones defined in the switch statement, you should return the current state. Instead, you are returning the initial state.
Try changing it to return the current state instead:
const initialState = {
CreateDatabaseTask: {
enabled: false,
type: "sqlite"
}
}
export default function (state = initialState, action) {
switch (action.type) {
case 'TASK_UPDATED':
var tasks = Object.assign({}, action.payload);
return tasks;
break;
default:
return state;
}
}