updating array object in redux phrasing error? - javascript

I am trying to update an array object in react.js by accessing the index of the object.
I have written this code and am getting this error.
Parsing error: ',' expected.eslint
updateUserAvatar: (
state,
{ payload: { id, avatar } }: PayloadAction<UpdateUserAvatar>
) => {
const users = current(state.data.familyMembers)
const user = users.find((user) => user.id === id) as DashboardFamilyMember
const userIndex = users.findIndex((user) => user.id === id)
return {
...state,
data: {
...state.data,
familyMembers: [
...state.data.familyMembers,
//where error occurs
userIndex: {
...user,
avatar: avatar,
},
],
},
}
},
},
I know I can map through the array but I am confused as to why this doesn't work.

You can map over familyMembers array and update when you find user.id and update that avatar.
const users = current(state.data.familyMembers)
const familyMembers = users.map(user => {
if(user.id === id) {
return { ...user, avatar };
} else {
return user;
}
}
const userIndex = users.findIndex((user) => user.id === id)
return {
...state,
data: {
...state.data,
familyMembers: familyMembers,
},
};

Related

How to fix the typeerror in react and typescript?

my code is like below,
itemDetails: async (parent, args, { dataSources: { someAPI } }) => {
const source = get(parent, 'source');
const id = get(parent, 'id');
if (id) {
let output;
if (source === 'source1') {
const data = await someAPI.getItem(id);
output = {
id: data.id,
name: data.name,
}
}
if (source === 'source2') {
const data = await someAPI.getItem(id);
output = {
id: data.id,
name: data.name,
}
}
if (output) {
return {
id: output.id,
name: output.name,
}
} else {
return {};
}
} else {
return {};
}
},
the above code works but if i return the output within each if condition like below code it throws error that
the type id? : any, name?: any cannot be assigned to id? undefined , name?: undefined type
itemDetails: async (parent, args, { dataSources: { someAPI } }) => {
const source = get(parent, 'source');
const id = get(parent, 'id');
if (id) {
if (source === 'source1') {
const data = await someAPI.getItem(id);
return { //returning here
id: data.id,
name: data.name,
}
}
if (source === 'source2') {
const data = await someAPI.getItem(id);
return { //returning here
id: data.id,
name: data.name,
}
}
} else { //no id
return {};
}
},
not sure what the problem is. could someone help me with this. thanks.

proper use of onCompleted for GraphQL mutations

I want to run the query first. The query returns an id which is then required for the mutation. Currently, there's an issue with the order of how both things run from the handleSubmit(). If the mutation is successful, the console should print console.log('Checking');but that does not happen. The only output I get on the console is What's the Idand the value is probably something that was stored in one of my previous attempts. If the id was derived from this particular round of query, I would have seen Workingon the log, but that doesn't happen either.
const [loadUsers, { loading, data, error }] = useLazyQuery(LoadUsersQuery, {
variables: {
where: { email: friendEmail.toLocaleLowerCase() },
},
onCompleted: () => getFriendId(),
});
const [
createUserRelationMutation,
{
data: addingFriendData,
loading: addingFriendLoading,
error: addingFriendError,
},
] = useCreateUserRelationMutation({
variables: {
input: {
relatedUserId: Number(id),
type: RelationType.Friend,
userId: 5,
},
},
onCompleted: () => addFriend(),
});
const getFriendId = () => {
console.log('Working');
if (data) {
console.log(data);
if (data.users.nodes.length == 0) {
console.log('No user');
setErrorMessage('User Not Found');
} else {
console.log('ID', data.users.nodes[0].id);
setId(data.users.nodes[0].id);
}
} else {
if (error) {
setErrorMessage(error.message);
}
}
};
const addFriend = () => {
console.log('Whats the Id', Number(id));
if (addingFriendData) {
console.log('Checking');
console.log(addingFriendData);
}
if (addingFriendError) {
console.log('errorFriend', addingFriendError.message);
setErrorMessage(addingFriendError.message);
}
};
const handleSubmit = () => {
loadUsers();
createUserRelationMutation();
};
Before this, I was trying this:
const [id, setId] = useState('');
const [friendEmail, setFriendEmail] = useState('');
const [loadUsers, { loading, data, error }] = useLazyQuery(LoadUsersQuery);
const [createUserRelationMutation, { data: addingFriendData, loading: addingFriendLoading, error: addingFriendError }] = useCreateUserRelationMutation();
const getFriendId = () => {
console.log('Email', friendEmail.toLocaleLowerCase());
loadUsers({
variables: {
where: { email: friendEmail.toLocaleLowerCase() },
},
});
if (data) {
console.log('ID', data.users.nodes[0].id);
setId(data.users.nodes[0].id);
}
addFriend();
};
const addFriend = () => {
console.log('Whats the Id', Number(id));
createUserRelationMutation({
variables: {
input: {relatedUserId: Number(id), type: RelationType.Friend, userId: 7 }
},
});
if (addingFriendData){
console.log('Checking')
console.log(data);
}
if(addingFriendError){
console.log('errorFriend', addingFriendError.message);
setErrorMessage(addingFriendError.message);
}
}
const handleSubmit = () =>
{getFriendId();};
However, in this case, the values of the id & other states weren't being updated timely. I was running a graphql query inside getFriendId()that returns an id, followed by a mutation (inside addFriend(), which uses the id, along with an input (email) that the user types in. The problem is that on the first attempt, the mutation works fine and with correct values. However, when I change the email address on the input and run the query/mutation again, the values from my previous attempt are being used.
In the second attempt, the mutation was still using the id that we got in the first attempt.
Edit:
onCompleted: (data) => getFriendId(data),
const getFriendId = (data: any) => {
console.log('Working');
if (data) {
console.log(data);
if (data.users.nodes.length == 0) {
console.log('No user');
setErrorMessage('User Not Found');
} else {
console.log('ID', data.users.nodes[0].id);
setId(data.users.nodes[0].id);
}
Updated Code:
const [friendEmail, setFriendEmail] = useState('');
const [errorMessage, setErrorMessage] = useState('');
const [loadUsers, { loading, data, error }] = useLazyQuery(LoadUsersQuery);
const [
createUserRelationMutation,
{
data: addingFriendData,
loading: addingFriendLoading,
error: addingFriendError,
},
] = useCreateUserRelationMutation();
const getFriendId = () => {
console.log('Email', friendEmail.toLocaleLowerCase());
loadUsers({
variables: {
where: { email: friendEmail.toLocaleLowerCase() },
},
});
if (data) {
if (data.users.nodes.length == 0) {
console.log('No user');
setErrorMessage('User Not Found');
} else {
console.log('ID', data.users.nodes[0].id);
setId(data.users.nodes[0].id);
addFriend(data.users.nodes[0].id);
}
} else {
console.log('No data');
if (error) {
setErrorMessage(error.message);
}
}
//addFriend();
};
const addFriend = (idd: any) => {
console.log('Whats the Id', Number(idd));
createUserRelationMutation({
variables: {
input: {relatedUserId: Number(idd), type: RelationType.Friend, userId: 9 }
},
});
if (addingFriendData){
console.log('Checking')
console.log(data);
}
if(addingFriendError){
console.log('errorFriend', addingFriendError.message);
setErrorMessage(addingFriendError.message);
}
}
const handleSubmit = () =>
{
getFriendId();
};
You don’t need state to store ID, instead pass the Id to addFriend method like show below
const [friendEmail, setFriendEmail] = useState('');
const [errorMessage, setErrorMessage] = useState('');
const _onLoadUserError = React.useCallback((error: ApolloError) => {
setErrorMessage(error.message);
}, []);
const [
createUserRelationMutation,
{
data: addingFriendData,
loading: addingFriendLoading,
error: addingFriendError,
called: isMutationCalled
},
] = useCreateUserRelationMutation();
const addFriend = React.useCallback((idd: Number) => {
console.log('Whats the Id', idd);
createUserRelationMutation({
variables: {
input: { relatedUserId: idd, type: RelationType.Friend, userId: 9 }
}
});
}, [createUserRelationMutation]);
const getFriendId = React.useCallback((data: any) => {
console.log('Email', friendEmail.toLocaleLowerCase());
if (data) {
if (data.users.nodes.length == 0) {
console.log('No user');
setErrorMessage('User Not Found');
} else {
console.log('ID', data.users.nodes[0].id);
addFriend(Number(data.users.nodes[0].id));
}
}
}, [friendEmail, addFriend]);
const [loadUsers] = useLazyQuery(LoadUsersQuery, {
onCompleted: getFriendId,
onError: _onLoadUserError
});
const handleSubmit = React.useCallback(() => {
loadUsers({
variables: {
where: { email: friendEmail.toLocaleLowerCase() },
}
});
}, [loadUsers, friendEmail]);
if (!addingFriendLoading && isMutationCalled) {
if (addingFriendData) {
console.log('Checking')
console.log(data);
}
if (addingFriendError) {
console.log('errorFriend', addingFriendError.message);
setErrorMessage(addingFriendError.message);
}
}
Update
I have updated the above code, please refer to it. I'm assuming useCreateUserRelationMutation does not accept options as argument, if it accepts option then you could use onCompleted and onError just like loadUsers query.

How do I trigger my redux function in my component

I have a form that is supposed to create a new user on submit. On handleCreate I need redux to trigger the addUser action and update the state thereby creating a new user but I don't seem to be calling the action correctly.
action.js
const addUser = payload => ({
payload,
type: ADD_USER,
});
reducer.js
const addUsers = (items, newItem) => {
const { id } = newItem;
items[id] = newItem;
return { ...items };
};
case ADD_USER: {
const { users } = state;
const { payload: { item } } = action;
return {
...state,
isUpdated: true,
users: addUsers(users, item),
};
}
The function to trigger the action in the component
handleCreate = () => {
const { form } = this.formRef.props;
const { addUser } = this.props.actions;
form.validateFields((error, values) => {
if (error) {
return error;
}
form.resetFields();
const user = {
age: values.age,
birthday: values[DATE_PICKER].format('YYYY-MM-DD'),
firstName: values.firstName,
hobby: values.hobby,
id: uuid(),
lastName: values.lastName,
};
addUser(user);
});
};
The problem you have is with destructuring the playload, const { payload: { item } } = action; expects the payload to have a key item
const action = {
payload: {
item: {
a: "a",
b: "b"
}
}
};
const {
payload: { item }
} = action;
console.log(item)
replace const { payload: { item } } = action; in your reducer with
const { payload: item } = action;
Looking at your actual project linked in the comments of the other answer, I found the source of your problem, your reducer for ADD_USER needs to be
case ADD_USER: {
const { users } = state;
return {
...state,
isUpdated: true,
users: addUsers(users, action.payload)
};
}
Before when you had const { payload: { item } } = action; you were expecting the action object to be shaped
{
type: WHATEVER_TYPE,
payload: { item: user }
},
But the action actually looks like
{
type: WHATEVER_TYPE,
payload: user,
},

How to use DataLoader with Mongoose

I'm trying to build the following use case of DataLoader together with Mongoose:
export const PurchaseOrderType = new GraphQLObjectType({
name: "PurchaseOrder",
description: "PurchaseOrder",
interfaces: () => [NodeInterface],
isTypeOf: value => value instanceof PurchaseOrderModel,
fields: () => ({
id: {
type: new GraphQLNonNull(GraphQLID),
resolve: obj => dbIdToNodeId(obj._id, "PurchaseOrder")
},
name: {
type: new GraphQLNonNull(GraphQLString)
},
customer: {
type: CustomerType,
resolve: (source, args, context) => {
return context.customerLoader.load(source.customer_id);
}
}
})
});
export default () => {
return graphqlHTTP((req, res, graphQLParams) => {
return {
schema: schema,
graphiql: true,
pretty: true,
context: {
customerLoader: customerGetByIdsLoader()
},
formatError: error => ({
message: error.message,
locations: error.locations,
stack: error.stack,
path: error.path
})
};
});
};
export const customerGetByIdsLoader = () =>
new DataLoader(ids => {
return customerGetByIds(ids);
});
export const customerGetByIds = async ids => {
let result = await Customer.find({ _id: { $in: ids }, deletedAt: null }).exec();
let rows = ids.map(id => {
let found = result.find(item => {
return item.id.equals(id);
});
return found ? found : null; << === found always undefined
});
return rows;
};
I'm facing the following problems when loading several PurchaseOrders:
A single customer_id is being called more than once in the ids parameter of the DataLoader. So an example id 5cee853eae92f6021f297f45 is being called on several requests to my loader, in successive calls. That suggests that the cache is not working properly.
My found variable when processing the read result is always being set to false, even comparing the right ids.
You can use findOne
export const customerGetByIds = async ids => {
let result = await Customer.find({ _id: { $in: ids }, deletedAt: null }).exec();
const rows = []
let promiseAll = ids.map(async (id) => {
let found = result.filter(item => item.id.toString() === id.toSring());
if(found) {
rows.push(found[0])
return found[0]
}
return null;
});
await Promise.all(promiseAll);
return rows;
};

While using redux, 'payload' property is undefined when the getter method is being invoked

I'm unable to access my property defined as a getter.
I've console.logged all segments feeding that property, so i think the getter definition is wrong.
export const messageThreadChecker = (_uid) => (dispatch, getState) => {
chatRef.child(_uid).on('value', snap => {
!snap.exists() && dispatch(finishThreadCheck(false));
dispatch(finishThreadCheck(!snap.val().isActivated ? {
status: 'pending'
} : {
status: 'active',
get payload() {
chatRef.child(snap.val()._tid + '/messages/').orderByKey().limitToLast(1).once('value', (_message) => {
var _lastRef = _.values(_message.val())[0]._id;
userRef.child(snap.val().provider.id)
.once('value').then((snapshot) => {
return {
correspondent: {
name: snapshot.val().name,
avatar: snapshot.val().avatar
},
threadId: snapshot.val()._tid,
lastRef: _lastRef,
}
})
})
}
}))
})
};
Upon attempting to access the payload property, I'm getting the following:
{status:'active',payload:undefined}
If a getter doesn't return anything than its property value is undefined.
Your payload getter function doesn't return anything because it has no return statement. Maybe you wanted this?
export const messageThreadChecker = (_uid) => (dispatch, getState) => {
chatRef.child(_uid).on('value', snap => {
!snap.exists() && dispatch(finishThreadCheck(false));
dispatch(finishThreadCheck(!snap.val().isActivated ? {
status: 'pending'
} : {
status: 'active',
get payload() {
return chatRef.child(snap.val()._tid + '/messages/').orderByKey().limitToLast(1).once('value', (_message) => {
var _lastRef = _.values(_message.val())[0]._id;
userRef.child(snap.val().provider.id)
.once('value').then((snapshot) => {
return {
correspondent: {
name: snapshot.val().name,
avatar: snapshot.val().avatar
},
threadId: snapshot.val()._tid,
lastRef: _lastRef,
}
})
})
}
}))
})
};

Categories