React + Redux state with multiple uses [closed] - javascript

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I don't have a code to share. I am using a template that's built using react + Redux.
The issue I ran into is that if I want multiple users to use the app, the state gets shared with everyone. It makes no difference between users. So the problem I have is one use will see the state of another user who just logged in before. Another one is I am fetching data to display in a chart and somehow the numbers are incrementing everytime it fetches and gets worse if multiple users are logged in.
My question is... How do you manage a react app with multiple users along with Redux? It seems most tutorial I found somehow assume there is only one user.

Most easiest solution is, if your APP is using database that fetched from an API, everytime you start your request, you should clear the data first
here's my reducer example (I'm using redux-tools)
reducers: {
getRoleDetailStart(state) {
state[CURRENT_NAMESPACE].data = {};
state[CURRENT_NAMESPACE].isLoading = true;
state[CURRENT_NAMESPACE].error = null;
},
getRoleDetailSuccess(state, action) {
const { data } = action.payload;
state[CURRENT_NAMESPACE].data = data;
state[CURRENT_NAMESPACE].isLoading = false;
state[CURRENT_NAMESPACE].error = null;
},
getRoleDetailError(state, action) {
state.isLoading = false;
state.error = action.payload;
},
},
actions
export const fetchRootGetRoleDetail = ({ roleId }) => async (
dispatch,
getState
) => {
const state = getState();
const selectedState = state[PARENT_NAMESPACE][CURRENT_NAMESPACE];
const { isLoading } = selectedState;
if (isLoading) return;
try {
dispatch(getRoleDetailStart());
const data = await restRootGetRoleDetail({
roleId,
});
dispatch(
getRoleDetailSuccess({
data,
})
);
} catch (err) {
if (isValidJSON(err)) {
return dispatch(getRoleDetailError(JSON.parse(err).message));
}
dispatch(getRoleDetailError(err));
}
};

Related

_query is not a function. (In '_query((0, _database.ref) [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 15 hours ago.
Improve this question
I am getting an Error when using database _query
Error
ERROR TypeError: _query is not a function. (In '_query((0, _database.ref)(_FirebaseConfig.database, 'users'), (0, _database.orderByChild)('email'), (0, _database.equalTo)(email))', '_query' is undefined)
code:
(note that query is not being highlighted as used )
import { ref, get, set, orderByChild, equalTo, query } from 'firebase/database';
useEffect(() => {
const writeToDatabase = () => {
const email = UserDataFromGoogleAuth.email;
if (email) {
const query = query(ref(database, 'users'), orderByChild('email'), equalTo(email));
get(query)
.then((snapshot) => {
const uuid = snapshot.exists() ? Object.keys(snapshot.val())[0] : uid();
const userRef = ref(database, `/users/${uuid}`);
const userData = {
id: uuid,
name: UserDataFromGoogleAuth.displayName,
email: email,
profilePicture: UserDataFromGoogleAuth.photoURL,
};
return set(userRef, userData);
})
}
};
writeToDatabase();
}, [location, UserDataFromGoogleAuth, props.online, database]);
**
"firebase": "^9.17.1",**
I am getting an Error when using database _query
On this line:
const query = query(ref(database, 'users'), orderByChild('email'), equalTo(email));
You define a variable called query and then try to assign it a value based on calling that same uninitialized variable because it shadow's the query method you are importing from the firebase/database library.
Rename the variable to something else to prevent shadowing the imported method.
const usersWithMatchingEmailQuery = query(ref(database, 'users'), orderByChild('email'), equalTo(email));
get(usersWithMatchingEmailQuery)
.then(/* ... */)
Note: Don't forget to add a catch() to that Promise chain to handle errors.

useState not updating my variable and other solutions aren't working either

I know there are plenty of answers related to this topic but I've tried all of them, using useEffect, and it still doesn't work. What I'm trying to do is to update a variable called currentAccount when the app loads and then each time the account changes (this is an app using Metamask).
So when the website loads:
useEffect(() => {
if (!walletConnected) {
[...]
onPageLoad();
}
}, [walletConnected,currentAccount]);
Then, as can be seen, I connect to the connect, select the role of the user logged and there is a listener Metamask provides that listens to an event called 'accountschanged' and when that event is triggered, changes the currentAccount state and again check the role of the new account.
const onPageLoad = async () => {
await connectWallet();
await getUserRole();
window.ethereum.on('accountsChanged', function (accounts) {
setCurrentAccount(accounts[0]);
getUserRole();
})
};
The connectWallet is the one responsible for the first time to update the currentAccount from the default value '' to the current account. The problem is that it doesn't update the value...
const connectWallet = async () => {
// we need to gain access to the provider/signer from Metamask
try {
const provider = await getProviderOrSigner();
let accounts = await provider.send("eth_requestAccounts", []);
setCurrentAccount(accounts[0]);
setWalletConnected(true);
return provider;
} catch (error) {
console.log(error);
}
};
What am I doing bad?? Any idea? I can share with you more code if needed. I know it's a long question but I wanted to give as many details as needed.
Thanks a looott!!!!

How to implement this without triggering an infinite loop with useEffect

So I have a situation where I have this component that shows a user list. First time the component loads it gives a list of all users with some data. After this based on some interaction with the component I get an updated list of users with some extra attributes. The thing is that all subsequent responses only bring back the users that have these extra attributes. So what I need is to save an initial state of users that has a list of all users and on any subsequent changes keep updating/adding to this state without having to replace the whole state with the new one because I don't want to lose the list of users.
So far what I had done was that I set the state in Redux on that first render with a condition:
useEffect(() => {
if(users === undefined) {
setUsers(userDataFromApi)
}
userList = users || usersFromProp
})
The above was working fine as it always saved the users sent the first time in the a prop and always gave priority to it. Now my problem is that I'm want to add attributes to the list of those users in the state but not matter what I do, my component keeps going into an infinite loop and crashing the app. I do know the reason this is happening but not sure how to solve it. Below is what I am trying to achieve that throws me into an infinite loop.
useEffect(() => {
if(users === undefined) {
setUsers(userDataFromApi)
} else {
//Users already exist in state
const mergedUserData = userDataFromApi.map(existingUser => {
const matchedUser = userDataFromApi.find(user => user.name === existingUser.name);
if (matchedUser) {
existingUser.stats = user.stats;
}
return existingUser;
})
setUsers(mergedUserData)
}
}, [users, setUsers, userDataFromApi])
So far I have tried to wrap the code in else block in a separate function of its own and then called it from within useEffect. I have also tried to extract all that logic into a separate function and wrapped with useCallback but still no luck. Just because of all those dependencies I have to add, it keeps going into an infinite loop. One important thing to mention is that I cannot skip any dependency for useCallback or useEffect as the linter shows warnings for that. I need to keep the logs clean.
Also that setUsers is a dispatch prop. I need to keep that main user list in the Redux store.
Can someone please guide me in the right direction.
Thank you!
Since this is based on an interaction could this not be handled by the the event caused by the interaction?
const reducer = (state, action) => {
switch (action.type) {
case "setUsers":
return {
users: action.payload
};
default:
return state;
}
};
const Example = () => {
const dispatch = useDispatch();
const users = useSelector(state => state.users)
useEffect(() => {
const asyncFunc = async () => {
const apiUsers = await getUsersFromApi();
dispatch({ type: "setUsers", payload: apiUsers });
};
// Load user data from the api and store in Redux.
// Only do this on component load.
asyncFunc();
}, [dispatch]);
const onClick = async () => {
// On interaction (this case a click) get updated users.
const userDataToMerge = await getUpdatedUserData();
// merge users and assign to the store.
if (!users) {
dispatch({ type: "setUsers", payload: userDataToMerge });
return;
}
const mergedUserData = users.map(existingUser => {
const matchedUser = action.payload.find(user => user.name === existingUser.name);
if (matchedUser) {
existingUser.stats = user.stats;
}
return existingUser;
});
dispatch({ type: "setUsers", payload: mergedUserData });
}
return (
<div onClick={onClick}>
This is a placeholder
</div>
);
}
OLD ANSWER (useState)
setUsers can also take a callback function which is provided the current state value as it's first parameter: setUsers(currentValue => newValue);
You should be able to use this to avoid putting users in the dependency array of your useEffect.
Example:
useEffect(() => {
setUsers(currentUsers => {
if(currentUsers === undefined) {
return userDataFromApi;
} else {
//Users already exist in state
const mergedUserData = currentUsers.map(existingUser => {
const matchedUser = userDataFromApi.find(user => user.name === existingUser.name);
if (matchedUser) {
existingUser.stats = user.stats;
}
return existingUser;
});
return mergedUserData;
}
});
}, [setUsers, userDataFromApi]);

Component unable to fetch data from Firebase when navigating to it for the first time or coming back

Background
I'm building an app which displays a number of stores in the home screen. They are shown in a carousel which is filled up with information from a Firestore Collection and Firebase Storage. The user can navigate into each store by pressing on them. The Home Screen display works just fine every single time, but when navigating to one store components come back as undefined. This is the way I'm fetching the data:
export default function StoreDetailMain ({route}) {
const { storeId } = route.params
const [store, setStore] = useState()
useEffect(() => {
const fetchQuery = async () => {
const storeData = await firebase.firestore()
.collection('stores/')
.doc(storeId)
.get()
.then(documentSnapshot => {
console.log('Store exists: ', documentSnapshot.exists);
if (documentSnapshot.exists) {
console.log('Store data: ', documentSnapshot.data());
setStore(documentSnapshot.data())
console.log(documentSnapshot.data())
}
});
}
fetchQuery()
}, [storeId])
Then I'm rendering the information within tags as in <Text>{store.value}</Text>.
Problem
Navigating once to the store will always return a Component Exception: undefined is not an object (evaluating 'store.value'). However if I cut the "{store.value}" tags it works just fine. Then I can manually type them in again and they render perfectly. Once I go back to the Home Screen and try to go into another store I have to do it all again. Delete the calls for information within the return(), save the code, reload the app and type them in again.
What I have tried
Sometimes, not always, Expo will give me a warning about not being able to perform a React state update on an unmounted component. I thought this might be the problem so I gave it a go by altering my useEffect method:
export default function StoreDetailMain ({route}) {
const { storeId } = route.params
const [store, setStore] = useState()
useEffect(() => {
let mounted = true;
if(mounted){
const fetchQuery = async () => {
const storeData = await firebase.firestore()
.collection('stores/')
.doc(storeId)
.get()
.then(documentSnapshot => {
console.log('Store exists: ', documentSnapshot.exists);
if (documentSnapshot.exists) {
console.log('Store data: ', documentSnapshot.data());
setBar(documentSnapshot.data())
console.log(documentSnapshot.data())
}
});
}
fetchQuery()
}
return () => mounted = false;
}, [storeId])
This would not solve the issue nor provide any variation.
Question
Is this due to the unmounting/mounting of components? If so, wouldn't the useEffect method take care of it? If anyone could provide an explanation/solution it would be very much appreciated.
Thanks in advance.
Edit 1:
When the application fails to render the information, it doesn't print into the console the document snapshot. When it can render the data, it does log it. Thus the change in title.
try giving it a initial value
const [ store, setStore ] = useState({value: ''})
or render it conditionally
{ store?.value && <Text>{store.value}</Text> }
secondly, route.params is defined? When you switching screens, did u make sure u pass the params? Switching from stack navigator to tab navigator for example, may drop the params.

Passing all http requests and React Routes through node backend first for session verification and then return path [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I'm trying to pass all http requests and React Routes through a node backend to verify session.
I am also using webpack-dev-server, so I assume in my dev environment I will need to use the proxy feature.
But once the request hits the node server, I'm not sure how to pass the results back to react front end and proceed with the normal react router page.
Something like:
1. Click React Router link to /contact
/contact route in node verifies session
Session is/isn't valid
If valid proceed with normal page load
If not valid return to homepage and change state.
I assume at least some of this will be done with lifecycle methods?
Is any of this possible without using front end functionality other than react router. I want to make this entirely back end dependent to verify the existing session or generate a new session.
React handles all routing on the client side, if you want to access /contact outside your web app you must have something like this:
app.get('*', (req, res) => {
res.render('index');
});
If you want to handle a predefined route you can also do this:
// Path can be anything you want check in this case any route
app.use('/', (req, res, next) => {
const { token } = req.cookies;
if (!token) {
res.status(400).send({ data: 'error' });
} else {
// Verifying some token function
verifyIdToken(token)
.then((claims) => {
// Perform some operations or assignments
req.claims = claims;
// Countinue
next();
})
.catch((error) => {
res.status(400).send({ data: 'error', message: error });
});
}
});
But if you want to verify session in the client I suggest making a call to an '/authenticate' route, then update your state accordingly to your response, for example:
I have a Home component, it can only be visible to logged users, so I created a high order component to wrap it that looks like this:
hoc-admin.js
// Generic validation method
const isEmpty = prop => (
prop === null ||
prop === undefined ||
(prop.hasOwnProperty('length') && prop.length === 0) ||
(prop.constructor === Object && Object.keys(prop).length === 0)
);
// This receives the props I want to check and the component to render
const userHOC = (props, Comp) => (WrappedComponent) => {
return class userHOC extends Component {
render() {
let valid = false;
props.map((prop) => {
valid = this.props && !isEmpty(this.props[prop])
// You can also check redux state props
// valid = this.props.common && !isEmpty(this.props.common[prop])
});
return valid
? (
<WrappedComponent {...this.props} /> // My wrapped component (Home)
)
: (
<Comp {...this.props} /> // My parameter component (Login)
)
}
};
};
export default userHOC;
Then I just need to wrap every component that needs some prop to show, in this case we arre looking for users in my home component so:
import HocUser from '../hoc/hoc-user';
class Home extends Component {
...
}
export default HocUser(['user'], Login)(Home);
``

Categories