I am trying to update my state with the new following array, however Even though the console shows no errors and prints out the new array correctly as it should be formed, the state does not update to reflect this.
What am I doing wrong?
state = {
notes: [
{
text: "mow the lawn",
author: "dean",
time: "10am"
},
{
text: "feed the dog",
author: "sam",
time: "2pm"
}
]
};
updateNotes = (title, name, eventTime) => {
let newNote = {
text: title,
author: name,
time: eventTime
};
this.setState(state => {
const list = state.notes.concat(newNote);
console.log(list); //shows the list formed correctly in the console
return {
list
};
});
};
Also for reference here is what I see in the console after running the code assuming I input the values, new text, some author, and 3pm when creating my new note
(3) [{…}, {…}, {…}]
0: {text: "mow the lawn", author: "dean", time: "10am"}
1: {text: "feed the dog", author: "sam", time: "2pm"}
2: {text: "new text", author: "some author", time: "3pm"}
It should be:
return {
notes: list
};
What you are doing now is adding a new variable list to the state.
Why do you update a field that is called list, even if your notes are inside field called notes?
{ list } is a shorthand to create an object with field called list and value that is stored in variable named in the same way.
Just update the proper field:
return {
notes: list,
};
Related
Here I am trying to modify my data over the iteration and send some result to API call.
The API Call receives a request with a structured data format which is
{ list: [{ id: "1", name: "Hello" }, ... ] }
Somehow I managed to call the API with single data ( const params in my current code, it only accepts single data).
But now it has to be done with multiple data something like this:
{ list: [{ id: "1", name: "Hello" }, { id: "22", name: "Ed" }, { id: "36", name: "Jason" } ... ] }
Here is my current code
const [table, setTalbe] = useState(..); // assume, we have some table data here
const processNow = () => {
let id = 0;
let name = '';
// if table length is greater than 1, we go for the loop.
if (table.length >= 1) {
table.map(data => {
id = data.userId;
name = data.userName;
});
//insert table data to params, here I want to add whole table data into "list"
//the final result of this list should be something like this
//ex ) list: [{ id: '123', name: 'Josh' }, { id: '125', name: 'Sue' }, { id: '2222', name: 'Paker' } ...],
// but how??
const params: any = {
list: [
{
id: id,
name: name
},
],
};
//send PUT reqeust with params
axios
.put(
'/api/v1/tosent',
params,
)
.then(res => {
console.log('The response', res);
})
.catch(err => {
console.log('The error: ', err);
});
}
};
but I'm stuck with it, please help me to finish this code to work properly.
need your kind advice.
Array.prototype.map returns a new array with the function you pass applied to every element. You should study the MDN documentation on map to understand its use.
Your current code does nothing with the map return value:
table.map(data => {
id = data.userId;
name = data.userName;
});
You probably assumed .map would mutate the data, as in change it in place. Instead, the whole operation returns a new array.
It looks like you want to do:
const list = table.map(data => {
return {
id: data.userId,
name: data.userName
}
});
This is applying a function to every element in the array that will map each element to a new object, matching your question, with an id and name key. Then it looks like you want to pass the returned value of map (which we named list above) to your call:
const params: any = {
list: list
};
I am very new to ReactJs. I have one requirement to compare both lists and then matched objects should return as output. These comparison should based on unique keys in the object i.e id, endTime.
Please have a look into below code.
From the below two Lists , I need to compare both of them based on unique keys (id, endTime), once it is matched or equal then need to return those objects as list.
Please help me on this.
The selected/ matched objects should return as output.
const apiResponse = [
{
id: 5520437,
startTime: 1498665761714,
endTime: 1498665824487,
},
{
id: 5520436,
startTime: 1498665761714,
endTime: 1498665824488,
},
{
id: 5520435,
startTime: 1498665761714,
endTime: 1498665824489,
},
{
id: 5520434,
start Time: 1498665761714,
endTime: 1498665824490,
}
]
const mySelectedData = [
{
id: 5520437,
start Time: 1498665761714,
endTime: 1498665824487,
},
{
id: 5520436,
start Time: 1498665761714,
endTime: 1498665824488,
},
]
I hope this is what you were looking for. Im comparing both of list and if given element of apiResponse is also an item of selected Data - is added to the result list
const tada = apiResponse.reduce(
(result, item) =>
mySelectedData.some(el => el.endTime === item.endTime)
? [...result, item]
: result,
[]
);
codesandbox -> https://codesandbox.io/s/runtime-smoke-bywti?fontsize=14
You can use filter
function myCompartor(arr){
return function(c){
return arr.filter(function(o){
return o.id == c.id
}).length == 0;
}
}
var common = apiResponse.filter(mySelectedData(mySelectedData));
I am using a combination of filter, some, and includes to return a filtered set of documents in my MongoDB/Node back-end environment.
While I can get this to work in a mock example, when I plug it in to my actual data, I get an error.
This is the key problematic piece of code:
let filteredDocs = docs.filter(doc => doc.branches._id.some(branch => mongoArrBranchID.includes(branch._id)));
When I console.log this out with:
console.log("filteredDocs: ", filteredDocs);
I get:
Reason: TypeError: Cannot read property 'some' of undefined
I've been scratching my head trying to figure out what the issue is here. Why is my mock example working, but not this?
One thought I had was that maybe the issue is that the comparison is made with different types. So then I checked with these two lines of code to make sure the comparison is using Mongo ObjectIDs in both cases (both return true):
console.log("is param value valid: ", mongoose.Types.ObjectId.isValid(mongoArrBranchID[0])); // returns true
console.log("is doc value valid: ", mongoose.Types.ObjectId.isValid(docs[0].branches[0]._id)); // returns true
So why am I getting the TypeError: Cannot read property 'some' of undefined error here?
By the way, just so you know what the data looks like, my passed-in filter values when consoled out look like this :
console.log("mongoArrBranchID: ", mongoArrBranchID); // result below
mongoArrBranchID: [ 5ac26645121f0613be08185d, 5ac26645121f0613be08185a ]
And again, this check returns true:
console.log("is param value valid: ", mongoose.Types.ObjectId.isValid(mongoArrBranchID[0])); // returns true
My docs data looks like this when I console out the first of the docs:
console.log("doc branches: ", docs[0].branches); // result below
doc branches: [{"_id":"5ac26645121f0613be08185a","name":"New York"},{"_id":"5ac26645121f0613be08185d","name":"Los Angeles"},{"_id":"5ac26648121f0613be081862","name":"Charlotte"},{"_id":"5ac2664a121f0613be081869","name":"Chicago"},{"_id":"5ac2664a121f0613be08186e","name":"Seattle"}]
When I console out just the first branches._id value, like so:
console.log("doc branch: ", docs[0].branches[0]._id);
I get:
doc branch: 5ac26645121f0613be08185a
And again, this check on the whether the value is a valid Mongo Object ID returns true:
console.log("is doc value valid: ", mongoose.Types.ObjectId.isValid(docs[0].branches[0]._id)); // returns true
So what's the problem here? Why am I getting this error:
Reason: TypeError: Cannot read property 'some' of undefined
When I do:
let filteredDocs = docs.filter(doc => doc.branches._id.some(branch => mongoArrBranchID.includes(branch._id)));
console.log("filteredDocs: ", filteredDocs);
And for extra clarification, when I use mock data in ScratchJS in Chrome, this works for me:
let docs = [
{
_id: "5ba39a12179b771820413ad8",
name: "Samson",
branches: [{ _id: "3nc26645121f0613be08167r", name: "New York" }, { _id: "3fc26645121f0613be08185d", name: "Los Angeles" }, { _id: "2hc26648121f0613be081862", name: "Seattle" }, { _id: "7jc2664a121f0613be081869", name: "Chicago" }, { _id: "7ju2664a121f0613be08186e", name: "Charlotte" }],
updatedAt: "2018-09-20T13:01:06.709Z",
createdAt: "2018-09-20T13:01:06.709Z"
},
{ _id: "3ya39a12179b771820413af5", name: "Sarah", branches: [{ _id: "3nc26645121f0613be08167r", name: "New York" }, { _id: "5ac26645121f0613be08145d", name: "Miami" }, { _id: "5ac2664a121f0613be08154s", name: "Sacramento" }], updatedAt: "2018-09-20T13:01:06.709Z", createdAt: "2018-09-20T13:01:06.709Z" },
{ _id: "2sa39a12179b771820413gy4", name: "Tim", branches: [{ _id: "1rd26645121d5613be08167h", name: "Denver" }, { _id: "5ac2664a121f0613be08154s", name: "Sacramento" }], updatedAt: "2018-09-20T13:01:06.709Z", createdAt: "2018-09-20T13:01:06.709Z" }
];
let filterValues = ["5ac26645121f0613be08145d", "7ju2664a121f0613be08186e"];
let filteredDocs = docs.filter(doc => doc.branches.some(branch => filterValues.includes(branch._id)));
console.log(filteredDocs);
So what's the difference? Why does it work in the mock example but not with my actual data?
It is because docs.branches is an array, and therefore does not have the _id attribute you have accessed on it. You should revise your code to the following:
let filteredDocs = docs.filter(doc => doc.branches.some(branch => mongoArrBranchID.includes(branch._id)));
The error you received occurred because accessing an non-existent attribute of an object returns undefined, so doc.branches._id returned undefined, and trying to access an attribute of undefined, some in this case, throws an error.
EDIT:
I want to clarify that the mistake is you wrote doc.branches._id.some instead of doc.branches.some in your code. The issue is the _id part.
I'm attempting to both add and remove items in a multidimensional array stored in Vuex.
The array is a group of categories, and each category and have a sub-category (infinity, not simply a two dimensional array).
Example data set is something like this:
[
{
id: 123,
name: 'technology',
parent_id: null,
children: [
id: 456,
name: 'languages',
parent_id: 123,
children: [
{
id:789,
name: 'javascript',
parent_id: 456
}, {
id:987,
name: 'php',
parent_id: 456
}
]
}, {
id: 333,
name: 'frameworks',
parent_id 123,
children: [
{
id:777,
name: 'quasar',
parent_id: 333
}
]
}
]
}
]
....my question is, how do I best add and remove elements to this array, which is inside of a Vuex Store?
I normally manipulate simple arrays inside the Vuex Store using Vue.Set() to get reactivity. However, because I'm not sure how deep the nested array being manipulated is - I simply can't figure it out.
Here's an example of how I thought I could add a sub-category element using recursion:
export const append = (state, item) => {
if (item.parent_uid !== null) {
var categories = []
state.data.filter(function f (o) {
if (o.uid === item.parent_uid) {
console.log('found it')
o.push(item)
return o
}
if (o.children) {
return (o.children = o.children.filter(f)).length
}
})
} else {
state.data.push(item)
}
}
The first thing to understand is that vuex, or any other state management library based on flux architecture, isn't designed to handle nested object graph, let alone arbitrary/infinity nested objects that you mentioned. To make the matter worse, even with shallow state object, vuex works best when you define the shape of the state (all desired fields) upfront.
IMHO, there are two possible approaches you can take
1. Normalize your data
This is an approach recommended by vue.js team member [here][2].
If you really want to retain information about the hierarchical structure after normalization, you can use flat in conjunction with a transformation function to flatten your nested object by name to something like this:
const store = new Vuex.Store({
...
state: {
data: {
'technology': { id: 123, name: 'technology', parent_id: null },
'technology.languages': { id: 456, name: 'languages', parent_id: 123 },
'technology.languages.javascript': { id: 789, name: 'javascript', parent_id: 456 },
'technology.languages.php': { id: 987, name: 'php', parent_id: 456 },
'technology.frameworks': { id: 333, name: 'frameworks', parent_id: 123 },
'technology.frameworks.quasar': { id: 777, name: 'quasar', parent_id: 333 },
}
},
});
Then you can use Vue.set() on each item in state.data as usual.
2. Make a totally new state object on modification
This is the second approach mentioned in vuex's documentation:
When adding new properties to an Object, you should either:
Use Vue.set(obj, 'newProp', 123), or
Replace that Object with a fresh one
...
You can easily achieve this with another library: object-path-immutable. For example, suppose you want to add new category under languages, you can create a mutation like this:
const store = new Vuex.Store({
mutations: {
addCategory(state, { name, id, parent_id }) {
state.data = immutable.push(state.data, '0.children.0.children', { id, name, parent_id });
},
},
...
});
By reassigning state.data to a new object each time a modification is made, vuex reactivity system will be properly informed of changes you made to state.data. This approach is desirable if you don't want to normalize/denormalize your data.
I have some json data in file called countryData.json structured as so:
{
"info":"success",
"stats":
[{
"id":"1",
"name":"USA",
"type":"WEST"
},
//...
I'm using graphQL to access this data. I have created an object type in the schema for countries using the following:
const CountryType = new GraphQLObjectType({
name: "Country",
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
type: { type: GraphQLString },
})
});
I want to write a query that will allow me to access all of the elements of this array that have a certain "name" value(There can be multiple with the same name). I've written the following query, but it only returns the first match in the array:
const RootQuery = new GraphQLObjectType({
name:"RootQueryType",
fields:{
country: {
type: CountryType,
args: { type: { name: GraphQLString } },
resolve(parent, args){
return _.find(countryData.stats, {name: args.name});
}
}
}
});
The "_" comes from const _ = require('lodash');
Also, how can I just get every single item in the array?
I have not recreated the code, therefore I can not check if it would be executed correctly. This is code, that should work in my opinion (without trying). If you want to return array of elements you need to implement https://lodash.com/docs/#filter. Filter will return all objects from stats, which match the argument name. This will return correctly inside resolver function, however, your schema needs adjustments to be able to return array of countries.
You need probably rewrite the arguments as follows as this is probably not correct. You can check out how queries or mutation arguments can be defined https://github.com/atherosai/express-graphql-demo/blob/feature/2-json-as-an-argument-for-graphql-mutations-and-queries/server/graphql/users/userMutations.js. I would rewrite it as follows to have argument "name"
args: { name: { type: GraphQLString } }
You need to add GraphQLList modifier, which defines, that you want to return array of CountryTypes from this query. The correct code should look something like this
const RootQuery = new GraphQLObjectType({
name:"RootQueryType",
fields:{
country: {
type: CountryType,
args: { name: { type: GraphQLString } },
resolve(parent, args){
return _.find(countryData.stats, {name: args.name});
}
},
countries: {
type: new GraphQLList(CountryType),
args: { name: { type: GraphQLString } },
resolve(parent, args){
return _.filter(countryData.stats, {name: args.name});
}
}
}
});
Now if you call query countries, you should be able to retrieve what you are expecting. I hope that it helps. If you need some further explanation, I made the article on implementing lists/arrays in GraphQL schema as I saw that many people struggle with similar issues. You can check it out here https://graphqlmastery.com/blog/graphql-list-how-to-use-arrays-in-graphql-schema
Edit: As for the question "how to retrieve every object". You can modify the code in resolver function in a way, that if the name argument is not specified you would not filter countries at all. This way you can have both cases in single query "countries".