I am trying to print out user related items only.
So i am try to get items by requesting data to user id /api/items/:userid
I am using redux store
my server side code is like this
router.get("/:userid",(req, res) => {
// Item.find({ "owner.ownerName": `${req.params.userid}`})
Item.find({ "owner.id": `${req.params.userid}`})
.sort({
date: -1,
})
.then((items) => res.json(items));
console.log(req.user)
});
The problem is my front end request.
I don't know how to get user id inside ITEMACTION.
import {
GET_ITEMS,
ADD_ITEM,
DELETE_ITEM,
ITEMS_LOADING,
UPDATE_ITEM,
SUBSTRACT_ITEM,
} from "../actions/types";
import { tokenConfig } from "../actions/authActions";
import { returnErrors } from "../actions/errorActions";
import Axios from "axios";
export const getItems = () => (dispatch) => {
// will hit reducer
dispatch(setItemsLoading());
Axios.get("/api/items/")
.then((res) =>
dispatch({
type: GET_ITEMS,
payload: res.data,
})
)
.catch((err) => {
dispatch(returnErrors(err.response.data, err.response.status));
});
};
I actually tried to get user id from the redux store.
import store from '../store';
and inside getItems
store.getState().auth.user._id
the problem is that when i console.log in getItems the user id is always return null except first time after login. But when i look in redux dev tool. The user id is available
how can i get the userid
Hey you can get the getState as a second argument in the inner function along with the dispatch, using that you can access the updated state in an action.
Fixed Code:
export const getItems = () => (dispatch, getState) => {
// will hit reducer
const userId = getState().auth.user._id;
console.log(userId) // should output the updated data
dispatch(setItemsLoading());
Axios.get("/api/items/")
.then((res) =>
dispatch({
type: GET_ITEMS,
payload: res.data,
})
)
.catch((err) => {
dispatch(returnErrors(err.response.data, err.response.status));
});
};
store.getState doesn't return updated state, in order to get the updated state using store.getState() you need to subscribe to the state change.
const unsubscribe = store.subscribe(() => {
// logs the state data everytime an action is dispatched.
console.log("from listener: ", store.getState());
})
Details here
Related
I want to dispatch outside component. I want to use option 2 from this link [https://daveceddia.com/access-redux-store-outside-react/][1]. My code look like this
const loginUser = async (data) => {
return axios.get(url + "/sanctum/csrf-cookie").then(() => {
axios.post(url + '/api/login', data)
.then(res => {
return res.data
})
.catch((err) => {
console.log(err);
})
})
}
export const handleLogin = (data) => async (dispatch) => {
console.log('test');
try {
const user = await loginUser(data);
dispatch(actions.setUser(user));
} catch (err) {
console.log(err);
}
}
And into my component
const test = (e) => {
e.preventDefault;
handleLogin({email: 'test#test.pl', password: 'password'})
}
return (
<div className="container">
<h2>Login</h2>
<form onSubmit={handleSubmit(test)}>
//...
It doesn't finish code and it may contain mistakes but currently the most important for me is why this code doesn't work and if sometimes is wrong why doesn't show any error. I think that problem is in sync(dispatch). In this example I add console.log for test and it wasn't display. Without that function display console.log.
Redux thunk is added to the store too
const store = createStore(allReducers, composeWithDevTools(applyMiddleware(thunk)))
import store and use like this :
store.dispatch(actions.setUser(user));
and you can get state out of component with :
store.getState().items
you did not dispatch your actions in your component and in your action js .
you can call an action in component by props and dispatch and I could not see the props so I use useDispatch and call handleLogin action there.
use this in action.js file:
const user = await loginUser(data)(dispatch);
instead :
const user = await loginUser(data);
then in component:
import {useDispatch} from "react-redux";
const dispatch = useDispatch();
const test = (e) => {
e.preventDefault;
dispatch(handleLogin({email: 'test#test.pl', password: 'password'}))
}
I am using Firebase.auth() to authenticate a login with Google Firebase then I retrieve the UID and send it to my Redux Store. The UID is not being sent to the store unless I navigate to the next page then return to the login page. It seems my order of operations is off, how can I get the UID in my Redux store without haveing to re-login/ refresh the page.
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
id: ''
}
}
id (value) {
this.props.id(value);
}
handleLogin = (load) => {
const { email, password } = this.state
Firebase.auth()
.signInWithEmailAndPassword(email, password)
.then(async cred => {
return db.collection('users').doc(cred.user.uid).set({
test: 'test'
})
})
.then(() => this.props.navigation.navigate('AddProfiles'))
.catch(error => console.log(error))
const currentUser = firebase.auth().currentUser;
const userId = currentUser["uid"];
this.setState({
id: userId
})
this.props.id(this.state.id);
}
<TouchableOpacity style={styles.signupbutton}>
<Button
color='white'
title="Log in"
onPress={(payload) => this.handleLogin()}
/>
</TouchableOpacity>
const mapStateToProps = (state) => {
return {
counter: state.counter,
value: state.id
};
}
const mapDispatchToProps = dispatch => {
return {
id: (value) => dispatch({ type: 'id', payload: value })
}
};
export default connect(mapStateToProps, mapDispatchToProps)(Home)
Right now, the code starting with the line const currentUser is running before the signInWithEmailAndPassword completes, since signInWithEmailAndPassword is an asynchronous function. The reason that it works on refresh is at that point, firebase.auth().currentUser has a value, so
You can move your code inside the then block so that it runs only when the function is complete. It'll look something like this (untested, because I don't have the rest of your code):
handleLogin = (load) => {
const { email, password } = this.state
Firebase.auth()
.signInWithEmailAndPassword(email, password)
.then(async cred => {
this.setState({
id: cred.user.uid
})
this.props.id(cred.user.id);
return db.collection('users').doc(cred.user.uid).set({
test: 'test'
})
})
.then(() => this.props.navigation.navigate('AddProfiles'))
.catch(error => console.log(error))
}
Note that setState is also asynchronous, so calling this.props.id(this.state.id); right after setState is likely to fail on the first run.
Although the above should fix the immediate issue, I'd suggest onAuthStateChanged: https://firebase.google.com/docs/auth/web/start#set_an_authentication_state_observer_and_get_user_data
This way, you can do your sign in and set the Redux state based on its value or run the same code to set the Redux value when the user just returns to a page. It'll probably lead to a more robust situation than tying everything to signInWithEmailAndPassword
I have two action in my redux actions... now I have a login form that makes a post request.. now I want to call another action from within the login action.
Now i connected the login function but not the setLoading function
e.g
export const loginUser = ()=>dispatch=>{
setLoading();
}
export const setLoading = ()=>({
type: SET_LOADING
})
You can use the logic of this answer to help you. An example is given in this answer(That's an example of getting products).
React Redux fetching data from backend approach
For your problem, it's best to pay attention to this part of the link
I gave you above, since you can use that logic for your program.
Notice this in the link above
// redux/product/product.actions.js
import { ShopActionTypes } from "./product.types";
import axios from "axios";
export const fetchProductsStart = () => ({
type: ShopActionTypes.FETCH_PRODUCTS_START
});
export const fetchProductsSuccess = products => ({
type: ShopActionTypes.FETCH_PRODUCTS_SUCCESS,
payload: products
});
export const fetchProductsFailure = error => ({
type: ShopActionTypes.FETCH_PRODUCTS_FAILURE,
payload: error
});
export const fetchProductsStartAsync = () => {
return dispatch => {
dispatch(fetchProductsStart());
axios
.get(url)
.then(response => dispatch(fetchProductsSuccess(response.data.data)))
.catch(error => dispatch(fetchProductsFailure(error)));
};
};
Data is appending next to the datatable, not inside.
I am fetching data (array of records) from an API in actions of vuex and returning state (array) from getters to the components where datatables have been used.
import axios from "../../assets/constants";
import router from '../../router'
const state = {
users: []
}
const getters = {
users: state => state.users,
blockedUsers: state => state.blockedUsers,
user: state => state.user
}
const actions = {
async getUsers({ commit }) {
await axios.get(`user`)
.then(res => {
commit('setGetUsers', res.data)
})
.catch(err => console.log(err.response.data.message));
})
},
const mutations = {
setGetUsers: (state, newUsers) => (state.users = newUsers),
}
export default {
state,
getters,
actions,
mutations
}
<script>
import { mapGetters, mapActions } from "vuex";
export default {
methods: {
...mapActions(["getUsers"])
},
computed: mapGetters(["users"]),
created() {
this.getUsers();
$(".zero-configuration").DataTable();
}
};
</script>
Result should be as that data that I am fetching from API must show inside datatable.
As far I understand, issue that has been causing here is that
$(".zero-configuration").DataTable();
this is executing before
this.getUsers()
which shouldn't be correct explanation because I have used await with axios.
Can anyone explain why is this happening?
It turns out when I commit mutation after I get response from axios, it takes time to set the state. Since I am not using promise here, while the state is being mutate,
$(".zero-configuration").DataTable();
takes control from
this.getUsers()
and get executed before it finishes.
I encountered this problem by using promise in getUsers action
getUsers({ commit }) {
return new Promise(async (resolve) => {
await axios.get(`user`)
.then(async res => {
await commit('setGetUsers', res.data)
resolve()
})
.catch(err => console.log(err.response.data.message));
})
},
Now it works like a charm!
I have a react component in a Redux enabled application that starts by loading a list of ID's in a 2D array. (Each "page" is represented by an element of the outer array [1rst dimension])
Here is the component:
import React, { Component, Fragment } from "react";
import { loadInsiderPage, loadInsiderInfo } from "../../actions/insider";
import { connect } from "react-redux";
import IndividualInsider from "./individual";
import Paginate from "../common/paginate";
class InsiderList extends Component {
componentDidMount() {
if (this.props.insiderIds.length > 0) {
this.props.loadInsiderPage(this.props.insiderIds[0]);
} else {
this.props.loadInsiderInfo();
}
}
render() {
let { insiderIds, insiders } = this.props;
let insiderFormat = insiders.map(x => {
return <IndividualInsider key={x._id} insider={x} />;
});
return (
<Fragment>
<div className="container">
<Paginate
pages={insiderIds}
changePage={this.props.loadInsiderPage}
/>
{insiderFormat}
</div>
</Fragment>
);
}
}
export default connect(
null,
{ loadInsiderPage, loadInsiderInfo }
)(InsiderList);
This component will load the ID list if it's not filled by running the loadInsiderInfo() action, and if the ID list is not empty, it will trigger the page to be populated by running the loadInsiderPage() action which takes in a page from the ID list.
How can I have this trigger properly after the ID list has been loaded?
I was thinking I could do it in componentWillReceiveProps() but I'm not sure where to go with the nextProps property.
My actions are as follows:
export const loadInsiderInfo = () => dispatch => {
Axios.get("insider/list/pages/25")
.then(list => {
dispatch({ type: LOAD_INSIDER_LIST, payload: list.data });
})
.catch(err => dispatch({ type: GET_ERRORS, payload: err }));
};
export const loadInsiderPage = page => dispatch => {
console.log(page);
Axios.post("insider/page", { page })
.then(res => dispatch({ type: LOAD_INSIDER_PAGE, payload: res.data }))
.catch(err => dispatch({ type: GET_ERRORS, payload: err }));
};
Both simply grab data from the API and load it into the reducer.
The big issue that I'm coming across is that the Component will sometimes have props passed that keep the loadInsiderPage action from being called with a page object passed in.
In your action creator loadInsiderInfo() you can accept a param for the current page ID. Now when the Info is loaded, within this action creator you can dispatch another action by calling loadInsiderPage(id) in it. This way your page info is loaded for the first time by the insider info action creator itself.
Something like this:
export const loadInsiderInfo = (id) => dispatch => {
Axios.get("insider/list/pages/25")
.then(list => {
dispatch({ type: LOAD_INSIDER_LIST, payload: list.data });
if(<your-data-loaded>){
loadInsiderPage(id)(dispatch);
}
})
.catch(err => dispatch({ type: GET_ERRORS, payload: err }));
};
Now only call loadInsiderInfo(id) once, when there is no info loaded yet. For every other time, directly dispatch the loadInsiderPage(id) action instead. This way you handle every case, after the insider info data has been loaded.