redux toolkit dipatching buildercase twice actions - javascript

I am trying to figure out why during refresh does the dispatch action gets run twice and the endpoint is also been called twice.
This is my slice
extraReducers: (builder) => {
builder.addCase(fetchAppointments.pending, (state, action) => {
state.loading = true;
});
builder.addCase(fetchAppointments.fulfilled, (state, {payload}) => {
state.loading = false;
state.total = payload.total;
state.dates = payload.dates;
state.data = payload.data;
});
builder.addCase(fetchAppointments.rejected, (state, action) => {
state.loading = false;
state.total = {};
state.dates = [];
state.data = {};
});
},
In my component I have it set up this way
const { apptDates } = useSelector<AppState>((state: any) => {
return {
apptDates: state.appt
}
});
useEffect(() => {
dispatch(fetchAppointments());
}, [dispatch]);
Any ideas as to why the dispatch are called twice and the endpoint is call called twice in the network tab?

If you have React's <StrictMode> component in use, all useEffect will run twice in development mode. That's probably what is happening here.

Related

how to show the first letter of name and login name using redux login

I am using redux login and after login want to show the first letter of the user in span and user login details(name or email) in my header section so please give the solution??
here is my redux login code
const authSlice = createSlice({
name: "auth",
initialState: {
user: null,
error: "",
loading: false,
},
extraReducers: {
[Login.pending]: (state, action) => {
state.loading = true;
},
[Login.fulfilled]: (state, action) => {
state.loading = false;
localStorage.setItem("user", JSON.stringify({ ...action.payload }))
state.user = action.payload
},
[Login.rejected]: (state, action) => {
state.loading = false;
state.error = action.payload.message;
},
[SignUp.pending]: (state, action) => {
state.loading = true;
},
[SignUp.fulfilled]: (state, action) => {
state.loading = false;
localStorage.setItem("user", JSON.stringify({ ...action.payload }));
state.user = action.payload;
},
[SignUp.rejected]: (state, action) => {
state.loading = false;
state.error = action.payload.message;
},
[Logout.pending]: (state, action) => {
state.loading = true;
},
[Logout.fulfilled]: (state, action) => {
state.loading = false;
localStorage.removeItem("user", JSON.stringify({ ...action.payload }));
state.user = action.payload;
},
[Logout.rejected]: (state, action) => {
state.loading = false;
state.error = action.payload.message;
}
}
});
here is my header code where enter details is the section where we have to enter the user login details to show the first letter of the user and name?
function Header() {
const {user} = useSelector((state) => state.auth);
const dispatch = useDispatch();
const navigate = useNavigate();
const logout = () =\> {
dispatch(Logout());;
navigate("/");
};
const htmlCode = () =\> {
return (
<span className="user-setting d-inline-block">
<h3 className="username">{enter details}</h3>
<span className="usericon">{enter details}</span>
</span>
)
}
```
I am trying to insert the {user.name} and other also but did not work??
Did you set up the store and the asyncthunk?
Is the reducer really named auth inside the store?
If everything is working you need to know what is going inside the user on the state, i will assume its an object like { name, email}, if that is the case then in the render you just have to do this { user.email } and to get the first letter use user.username.charAt(0)
============
Just to inform, useSelector re render the component based on the piece of state you select, if you will use just the user its better to use useSelector(state => state.auth.user ), that just matter if you have a complex component because react is fast

Can't get the action.payload go to the state Redux Toolkit

So I'm new to React and Redux Toolkit, I've been trying to get some 'posts' from my localhost API, I do get the payload and it gets displayed in the Redux Dev Tools, nevertheless I can't get this payload to be put on the state.
My postSlice.js :
import { createSlice, createAsyncThunk } from "#reduxjs/toolkit";
import axios from "axios";
export const getPosts = createAsyncThunk("posts", async () => {
try {
const res = await axios({
method: "get",
url: `${process.env.REACT_APP_API_URL}api/post`,
withCredentials: true,
});
console.log(res.data);
return res.data;
} catch (err) {
return err.res.data;
}
});
const postsSlice = createSlice({
name: "posts",
initialState: {
posts: [],
loading: false,
error:"",
},
extrareducers: {
[getPosts.pending]: (state, action) => {
state.loading = true;
},
[getPosts.fulfilled]: (state, action) => {
console.log(action.payload);
state.loading = false;
state.posts = action.payload;
},
[getPosts.rejected]: (state, action) => {
state.loading = false;
state.posts = action.payload.message;
},
},
});
export default postsSlice.reducer;
Then I use the dispatch on a React Component
import { useDispatch } from "react-redux";
import { getPosts } from "../redux/features/postSlice";
const Thread = () => {
const [loadPost, setLoadPost] = useState(true);
const dispatch= useDispatch();
useEffect(() => {
if (loadPost ) {
dispatch(getPosts());
setLoadPost(false)
}
}, [loadPost, dispatch]);
return <div>Fil d'actualités</div>;
};
export default Thread;
Finally I get this on the State in Redux Dev Tool
posts(pin):[]
loading(pin): false
error(pin): ""
And this on the Action:
payload (pin): [{...}{...}{...}]
Also, through the pending, fulfilled and rejected states, loading won't change a bit, even if I pass it on true or false directly with VSCode nor the log I put on the fulfilled extra reducer, it's like the action doesn't affect the state at all, therefore I have the another reducer working fine with the async functions, any help would be much appreciated!
EDIT: My bad, i made a misspelling mistake, 'r' instead of 'R' in 'extraReducers' declaration, the kind of error you feel so dumb about
I think you should use extraRedcuer that way:
extraReducers: (builder) => {
builder.addCase(getPosts.pending, (state, action) => {
state.loading = true;
}),
builder.addCase(getPosts.fulfilled, (state, action) => {
console.log(action.payload);
state.loading = false;
state.posts = action.payload;
}),
builder.addCase(getPosts.rejected, (state, action) => {
state.loading = false;
state.posts = action.payload.message;
}),
},

Redux-toolkit usage with Typescript without state mutation

I'm working on a React project which is using Redux-Toolkit in JavaScript. I'm trying to shift project to TypeScript for debugging ease and Type Safety benefits. My Slices code is as
export const entitiesSlice = createSlice({
name: "entities",
initialState: initialentitiesState,
reducers: {
// getentityById
entityFetched: (state, action) => {
state.actionsLoading = false;
state.entityForEdit = action.payload.entityForEdit;
state.error = null;
},
// findentities
entitiesFetched: (state, action) => {
const { totalCount, entities } = action.payload;
state.listLoading = false;
state.error = null;
state.entities = entities;
state.totalCount = totalCount;
},
// createentity
entityCreated: (state, action) => {
state.actionsLoading = false;
state.error = null;
state.entities.push(action.payload.entity);
},
// updateentity
entityUpdated: (state, action) => {
state.error = null;
state.actionsLoading = false;
state.entities = state.entities.map(entity => {
if (entity.id === action.payload.entity.id) {
return action.payload.entity;
}
return entity;
});
},
// deleteentities
entitiesDeleted: (state, action) => {
state.error = null;
state.actionsLoading = false;
state.entities = state.entities.filter(
el => !action.payload.ids.includes(el.id)
);
},
}
}
});
But I think the assignment like this state.somevar=updatedval is doing state mutation which is not good. I want to declare my state Interface with readonly to avoid state mutation. I have gone through the Redux-Toolkit-Usage-With-Typescript, which I think should avoid state mutation but all code snippets seem to be doing state mutation. I want something like this
entityFetched: (state, action) => {
return {
...state,
actionsLoading:false,
entityForEdit:action.payload.entityForEdit,
error:null
}
}
Please guide me if I'm missing something or misinterpretting the meaning of state mutation.
Any broader advice for using TypeScript with React would be most welcomed!
Thanks a Lot!
Redux Toolkit's createReducer and createSlice APIs use the Immer library internally, which allows you to write "mutating" syntax in your reducers, but turns that into safe and correct immutably updates.
Please read through the new "Redux Essentials" core docs tutorial for further explanations on how Redux relies on immutability, and how Immer makes it safe to write "mutations" in your reducers.

Access the state of my redux app using redux hooks

I am migrating my component from a class component to a functional component using hooks. I need to access the states with useSelector by triggering an action when the state mounts. Below is what I have thus far. What am I doing wrong? Also when I log users to the console I get the whole initial state ie { isUpdated: false, users: {}}; instead of just users
reducers.js
const initialState = {
isUpdated: false,
users: {},
};
const generateUsersObject = array => array.reduce((obj, item) => {
const { id } = item;
obj[id] = item;
return obj;
}, {});
export default (state = { ...initialState }, action) => {
switch (action.type) {
case UPDATE_USERS_LIST: {
return {
...state,
users: generateUsersObject(dataSource),
};
}
//...
default:
return state;
}
};
action.js
export const updateUsersList = () => ({
type: UPDATE_USERS_LIST,
});
the component hooks I am using
const users = useSelector(state => state.users);
const isUpdated = useSelector(state => state.isUpdated);
const dispatch = useDispatch();
useEffect(() => {
const { updateUsersList } = actions;
dispatch(updateUsersList());
}, []);
first, it will be easier to help if the index/store etc will be copied as well. (did u used thunk?)
second, your action miss "dispatch" magic word -
export const updateUsersList = () =>
return (dispatch, getState) => dispatch({
type: UPDATE_USERS_LIST
});
it is highly suggested to wrap this code with { try } syntax and be able to catch an error if happened
third, and it might help with the console.log(users) error -
there is no need in { ... } at the reducer,
state = intialState
should be enough. this line it is just for the first run of the store.
and I don't understand where { dataSource } comes from.

Unable to read state updated by useReducer hook in context provider

I am using useReducer hook to manage my state, but it seems like I have a problem with reading updated state in my context provider.
My context provider is responsible to fetch some remote data and update the state based on responses:
import React, { useEffect } from 'react';
import useAppState from './useAppState';
export const AppContext = React.createContext();
const AppContextProvider = props => {
const [state, dispatch] = useAppState();
const initialFunction = () => {
fetch('/some_path')
.then(res => {
dispatch({ type: 'UPDATE_STATE', res });
});
};
const otherFunction = () => {
fetch('/other_path')
.then(res => {
// why is `state.stateUpdated` here still 'false'????
dispatch({ type: 'DO_SOMETHING_ELSE', res });
});
}
};
const actions = { initialFunction, otherFunction };
useEffect(() => {
initialFunction();
setInterval(otherFunction, 30000);
}, []);
return (
<AppContext.Provider value={{ state, actions }}>
{props.children}
</AppContext.Provider>
)
};
export default AppContextProvider;
and useAppState.js is very simple as:
import { useReducer } from 'react';
const useAppState = () => {
const reducer = (state, action) => {
switch (action.type) {
case 'UPDATE_STATE':
return {
...state,
stateUpdated: true,
};
case 'DO_SOMETHING_ELSE':
return {
...state,
// whatever else
};
default:
throw new Error();
}
};
const initialState = { stateUpdated: false };
return useReducer(reducer, initialState);
};
export default useAppState;
The question is, as stated in the comment above, why is state.stateUpdated in context provider's otherFunction still false and how could I access state with latest changes in the same function?
state will never change in that function
The reason state will never change in that function is that state is only updated on re-render. Therefore, if you want to access state you have two options:
useRef to see a future value of state (you'll have to modify your reducer to make this work)
const updatedState = useRef(initialState);
const reducer = (state, action) => {
let result;
// Do your switch but don't return, just modify result
updatedState.current = result;
return result;
};
return [...useReducer(reducer, initialState), updatedState];
You could reset your setInterval after every state change so that it would see the most up-to-date state. However, this means that your interval could get interrupted a lot.
const otherFunction = useCallback(() => {
fetch('/other_path')
.then(res => {
// why is `state.stateUpdated` here still 'false'????
dispatch({ type: 'DO_SOMETHING_ELSE', res });
});
}
}, [state.stateUpdated]);
useEffect(() => {
const id = setInterval(otherFunction, 30000);
return () => clearInterval(id);
}, [otherFunction]);

Categories

Resources