import Axios from "axios";
export const ChangeTodoCount = (newCount) => {
return {
type: "CHANGE_TODO_COUNT",
payload: newCount,
};
};
export const FetchToDo = () => {
return (dispatch) => {
Axios.get("http://localhost:2000/todo").then((response) => {
dispatch({
type: "GET_TODO",
payload: response.data,
});
dispatch({
type: "CHANGE_TODO_COUNT",
payload: response.data.length,
});
});
};
};
export const DeleteItem = (id) => {
Axios.delete("http://localhost:2000/todo/" + id).then({ FetchToDo });
};
I'm trying to call FetchToDo after i run DeleteItem.
how would i need to add the FetchToDo to do that?
Right now, when i clicked on the delete button, the list is deleted but i have to refresh the page to re-fetch the list.
`export const DeleteItem = (id) => {Axios.delete("http://localhost:2000/todo/" + id).then(()=>FetchToDo())};`
Related
I am trying to load the user data and display on my dashboard page, I have tried many methods but failed to do so. Anyone can help?
below is my dashboard page:
const Dashboard = (props) => {
const { user } = props.auth;
useEffect(() => {
getCurrentProfile();
}, []);
return (<Fragment>
<h1>Dashboard</h1>
<i className='fas fa-user'></i>Welcome
<p>{user && user.fullName}</p>
</Fragment>);
};
below is my redux action:
export const getCurrentProfile = () => async dispatch => {
const [user] = useState('')
await authAxios.get('/user/profile').then(res => {
const result = res.data.user.result;
dispatch({
type: GET_PROFILE,
payload: res.data
});
}).catch(error => {
dispatch({
type: PROFILE_ERROR,
payload: {
msg: error.response.statusText,
status: error.response.status
}
});
});
};
I learn react and try to get Redux to work so I use the Redux-logger. When dispatching two actions from App.js it works as the top image show "ALBUME_DATA_LOADED".
Then I make a dispatch from from another place and get this output:
I'm not sure I sent that "object, object" action I place breakpoint and console log and it's strange the react-logger it catching an action that I dont think I sent..
Any idea?
Here is the action types I use in the below code as userActionTypes:
File user.types.js:
export const userActionTypes = {
SAVE_USER_START: 'SAVE_USER_START',
SAVE_USER_SUCCESS: 'SAVE_USER_SUCCESS',
SAVE_USER_FAILURE: 'SAVE_USER_FAILURE',
};
Here is the action:
File user.actions.js;
import { userActionTypes } from './user.types';
import { withFirebase } from '../../firebase';
import * as ROLES from '../../constants/roles';
const saveUserStart = () => ({
type: userActionTypes.SAVE_USER_START,
});
const saveUserSuccess = user => ({
type: userActionTypes.SAVE_USER_SUCCESS,
payload: user,
});
const saveUserFailure = errMsg => ({
type: userActionTypes.SAVE_USER_FAILURE,
payload: errMsg,
});
const asyncSaveUser = ({ firestore }) => {
return async dispatch => {
const userRef = firestore.userDoc(firestore.auth.currentUser.uid);
dispatch(saveUserStart());
firestore.db
.runTransaction(transaction => {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(userRef).then(doc => {
if (!doc.exists) {
return Promise.reject('Transaction failed: User dont exist!');
}
const newRoles = doc.data().roles;
// new roll
newRoles.push(ROLES.USER);
// remove roll
newRoles.splice(newRoles.indexOf('ANONYMOUS'), 1);
// save it back
transaction.update(userRef, { roles: newRoles });
return newRoles;
});
})
.then(newRoles => {
dispatch(saveUserSuccess());
console.log(`Transaction successfully committed role(s): ${newRoles}`);
})
.catch(error => {
dispatch(saveUserFailure(error));
console.log(error);
});
};
};
export default withFirebase(asyncSaveUser);
in dispatch saveUserSuccess(), you can't pass newRoles.
dispatch(saveUserSuccess(newRoles));
The reason for this is your mapDispatchToProps.
const mapDispatchToProps = dispatch => ({
saveUser: () => dispatch(asyncSaveUser())
});
asyncSaveUser() is not an action creator.
I'm using react redux to create an action creator in my app. The point is that when I use async await syntax, it auto returns a promise (without the "return" keyword). However, when I use old-style promise like then(), i have to explicitly type the "return" keyword - otherwise it will return undefined. Why does this happen?
app.js (createStore):
app.get('*', (req, res) => {
const store = createStore(reducers, applyMiddleware(reduxThunk));
const promise = matchRoutes(RouteApp, req.path).map(({ route }) => {
return route.loadData ? route.loadData(store) : null;
});
console.log(promise);
Promise.all(promise).then(() => {
res.send(renderApp(req, store));
});
});
route.js:
export default [
{
loadData,
path: '/',
component: Landing,
exact: true,
},
];
landing.js
function loadData(store) {
return store.dispatch(fetchUser());
}
export { loadData };
When I use async await:
action.js
export const fetchUser = () => async (dispatch) => {
const res = await axios.get('https://react-ssr-api.herokuapp.com/users');
dispatch({
type: INFO_USER,
payload: res.data,
});
};
When I use promise then:
// It doesn't work
export const fetchUser = () => (dispatch) => {
axios.get('https://react-ssr-api.herokuapp.com/users').then((res) => {
dispatch({
type: INFO_USER,
payload: res.data,
});
});
};
"return" keyword
// now it works
export const fetchUser = () => (dispatch) => {
return axios.get('https://react-ssr-api.herokuapp.com/users').then((res) => {
dispatch({
type: INFO_USER,
payload: res.data,
});
});
};
async function always returns a promise, that's its purpose. In case there's no return value, it returns a promise of undefined.
As the reference states,
Return value
A Promise which will be resolved with the value returned by the async
function, or rejected with an uncaught exception thrown from within
the async function.
This async function
export const fetchUser = () => async (dispatch) => {
const res = await axios.get('https://react-ssr-api.herokuapp.com/users');
dispatch({
type: INFO_USER,
payload: res.data,
});
};
is syntactic sugar for this function:
export const fetchUser = () => (dispatch) => {
return axios.get('https://react-ssr-api.herokuapp.com/users').then((res) => {
dispatch({
type: INFO_USER,
payload: res.data,
});
});
};
I am using redux-thunk and want like to dispatch an action and once that is finished make an api call with part of that updated store.
store.js
const middleware = composeEnhancers(applyMiddleware(promise(), thunk, logger()))
const localStore = loadStore()
const store = createStore(reducer, localStore, middleware)
graphActions.js:
First add an Element:
export function addElement(element) {
return dispatch => {
dispatch({
type: ADD_ELEMENT,
payload: element
})
}
}
Then make api call via different action creator:
export function saveElements() {
return (dispatch, getState) => {
let graphId = getState().elements.id
let elements = getState().elements.elements
axios.put(Config.config.url + '/graph/' + graphId, {
'data': JSON.stringify({elements: elements}),
}).then(() => {
dispatch({type: SHOW_SUCCESS_SNACKBAR})
}).catch((err) => {
dispatch({type: SHOW_ERROR_SNACKBAR})
dispatch({type: UPDATE_ELEMENTS_REJECTED, payload: err})
})
}
}
I need to make sure, that addElement() is finished before saveElements(), so that saveElements() accesses the updated store.
I tried the following:
export function addElement(element) {
const promise = (dispatch) => new Promise((resolve) => {
dispatch({
type: ADD_ELEMENT,
payload: element
})
resolve()
})
return dispatch => {
promise(dispatch).then(() => {
saveElements()
})
}
}
ADD_ELEMENT is dispatched, but the actions within saveElements() are not dispatched, no api call is made.
I was missing to dispatch saveElements() and returning dispatch(saveElements()).
export function addElement(element) {
const promise = (dispatch) => new Promise((resolve) => {
dispatch({
type: ADD_ELEMENT,
payload: element
})
resolve()
})
return (dispatch) => {
return addElements(dispatch).then(() => {
return dispatch(saveElements())
})
}
UPDATE:
Noticed I can simply do:
export function addElement(element)
return (dispatch) => {
dispatch({
type: ADD_ELEMENT,
payload: element
})
dispatch(saveElements())
})
}
I was testing redux actions using Jest , When i try to test the default action, it throws an Error
Expected value to equal:
{"payload": {"male": "mancha"}, "type": "actions/change_gender"}
Received:
[Function anonymous]
It seems it sends the function, instead of values.
test change_gender.js
import changeGender, { CHANGE_GENDER } from '../change_gender';
const payload = {
type: CHANGE_GENDER,
payload: {
male: 'mancha'
}
};
describe('actions', () => {
it('should Change the ', () => {
const expectedAction = {
type: payload.type,
payload: payload.payload
};
expect(changeGender('male', 'mancha')).toEqual(expectedAction)
});
});
Action change_gender.js
import toggleToolTip from './toggle_tooltip'; // eslint-disable-line
export const CHANGE_GENDER = 'actions/change_gender';
export default(radioType, type) => (dispatch) => {
dispatch({
type: CHANGE_GENDER,
payload: {
[radioType]: type
}
});
};
You should return the dispatch at change_gender.js:
change_gender.js:
import toggleToolTip from './toggle_tooltip'; // eslint-disable-line
export const CHANGE_GENDER = 'actions/change_gender';
export default(radioType, type) => (dispatch) => {
return dispatch({
type: CHANGE_GENDER,
payload: {
[radioType]: type
}
});
};
As Chen-tai mentioned, returning from the dispatch would help here for testing purposes.
The reason you see [Function] being returned is that your action is a function returning a function.
(radioType, type) => (dispatch) => { ... }
The first set of params, followed by the fat arrow is an anonymous function. That then returns another anonymous function that takes a dispatch function as its arguments. So, if we call the action twice, providing a mock dispatch function, we'll get back the expected action!
const action = (radioType, type) => (dispatch) => {
return dispatch({
type: "CHANGE_GENDER",
payload: {
[radioType]: type
}
});
};
console.log(
action('male', 'mancha')((action) => action)
)
We can then write out test:
Action change_gender.js
import toggleToolTip from './toggle_tooltip'; // eslint-disable-line
export const CHANGE_GENDER = 'actions/change_gender';
export default(radioType, type) => (dispatch) => {
return dispatch({
type: CHANGE_GENDER,
payload: {
[radioType]: type
}
});
};
test change_gender.js:
import changeGender, { CHANGE_GENDER } from '../change_gender';
const payload = {
type: CHANGE_GENDER,
payload: {
male: 'mancha'
}
};
describe('actions', () => {
it('should Change the ', () => {
const expectedAction = {
type: payload.type,
payload: payload.payload
};
expect(changeGender('male', 'mancha')((payload) => payload).toEqual(expectedAction)
});
});