How to destructure object in React with special characters in key - reactjs

Backend returns an object, and one of the key-value, I would handle differently, how can I split up object?
useEffect(() => {
const tempUserShortId = getTempUserShortId()
axios({
method: 'get',
url: `questionList?tempUserId=${tempUserShortId}&questionIds[]=6f50dbea-196b-4fb6-82ee-fbade62aab98&questionIds[]=6f50dbea-196b-4fb6-82ee-fbade62aab99&questionIds[]=6f50dbea-196b-4fb6-82ee-fbade62aab9a`,
headers: { crossDomain: true },
}).then((res) => {
const {'6f50dbea-196b-4fb6-82ee-fbade62aab9a', ...rest} = res.data;
setQuestions(rest)
})
}, [ind])
It says: ':' expected.ts(1005
Found this online:
const removeKey = () => {
setEmployee(current => {
// 👇️ remove salary key from object
const {salary, ...rest} = current;
return rest;
});
};
https://bobbyhadz.com/blog/react-remove-key-from-state-object
It does not work.
Got back from backend a structure like this:
{
"6F50DBEA-196B-4FB6-82EE-FBADE62AAB99": {
"text": "Mennyire forradalmi az ETH 2.0 bevezetése?",
"options": {
"1CD0D2C0-7494-4BE6-ADE6-E454816B584E": {
"text": "Forradalmi mert PoW helyett PoS lesz. Kevesebb energiát fog fogyasztani a rendszer. Viszont ez még mindig nem skálázható megoldás, a shardingot még nem tudja, és még hosszú évekig nem is fogja tudni, így a tranzakciós díj ugyanúgy magas fog maradni.",
"rating": {}
}
}
},
"6F50DBEA-196B-4FB6-82EE-FBADE62AAB98": {

You have to focus the key of your object and set it to "_" to tell that you will not use it
const obj = {
"6f50dbea-196b-4fb6-82ee-fbade62aab9a": "cool",
name: "test",
value: 3
}
const {"6f50dbea-196b-4fb6-82ee-fbade62aab9a": _, ...rest} = obj // rest equal {name: "test", value: 3}

Related

Can't use the data from API when app just starts

My data is undefined when the app is started but after the refresh, the data comes perfectly.
For startup
It gives me [Unhandled promise rejection: TypeError: Object.entries requires that input parameter not be null or undefined]
But after the refresh, the data comes perfectly and everything working.
This is part of my data
Object {
"attributes": Object {
"htmlName": null,
"id": 0,
"items": Array [
Object {
"htmlName": "r_1",
"name": "m2 (Brüt)",
"numeric": true,
"options": Object {},
"order": 0,
"required": true,
},
Object {
"htmlName": "r_2",
"name": "m2 (Net)",
"numeric": true,
"options": Object {},
"order": 0,
"required": true,
},
Object {
"htmlName": "r_164",
"name": "Arsa Alanı (m2)",
"numeric": true,
"options": Object {},
"order": 0,
"required": true,
},
Object {
"htmlName": "a_137",
"name": "Oda Sayısı",
"numeric": false,
"options": Object {
"12": "1+0",
"13": "1+1",
"14": "1.5+1",
"15": "2+0",
"16": "2+1",
"17": "2.5+1",
"18": "2+2",
"19": "3+1",
"20": "3.5+1",
"21": "3+2",
"22": "4+1",
"226": "0+1",
"23": "4.5+1",
"24": "4+2",
"25": "4+3",
"26": "4+4",
"27": "5+1",
"28": "5+2",
"29": "5+3",
"30": "5+4",
"31": "6+1",
"32": "6+2",
"33": "6+3",
"34": "7+1",
"35": "7+2",
"36": "7+3",
"37": "8+1",
"38": "8+2",
"39": "8+3",
"40": "8+4",
"41": "9+1",
"42": "9+2",
"43": "9+3",
"44": "9+4",
"45": "9+5",
"46": "9+6",
"47": "10+1",
"48": "10+2",
"49": "10 Üzeri",
},
"order": 0,
"required": true,
},
api.js
export const getData = function () {
return axios
.get(
"blabla",
{
headers: {
Authorization: `blabla`,
},
}
)
.then((json) => {
if (json && json.status === 200) {
//console.log(json);
return json.data;
}
})
.catch((e) => {
console.log(e);
});
};
App.js
const [data, setData] = useState({});
const [roomValue, setRoomValue] = useState(null);
const [roomCount, setRoomCount] = useState([]);
const [isFocus, setIsFocus] = useState(false);
useEffect(() => {
getDataFunc();
//setDropdown(data.attributes.items[3].options);
}, []);
const getDataFunc = async () => {
const res = await getData();
//console.log(res);
setData(res);
console.log(data);
};
function setDropdown(query) {
const response = query;
try {
const entries = Object.entries(response);
const tempArray = [];
for (let i = 0; i < entries.length; i++) {
var key;
var value;
(key = entries[i][0]), (value = entries[i][1]);
tempArray.push({ key: value, value: key });
}
setRoomCount(tempArray);
//console.log(roomCount);
} catch (error) {
//console.log(error);
}
}
How can I fix that ?
Add a seperate useEffect to check wheather the data has been set and then only set the dropdown values
useEffect(() => {
getDataFunc();
}, []);
useEffect(() => {
if(data && data.attributes?.items[3]){
setDropdown(data.attributes.items[3].options);
}
}, [data]);
const getDataFunc = async () => {
const res = await getData();
//console.log(res);
setData(res);
console.log(data);
};
It seems like the error is caused by the attributes property being empty when you try to access it. But when you assign them one by one then it loads because the data is loaded per nested property before assigning it to the variable. Means it hasn't fully loaded yet
const response = data.attributes.items[3].options;
It outputs an error because attributes is undefined. So it's not an object, therefore, attributes.items is considered invalid
// sample
const data = {
/* attributes: {
items: {
1: {
options: 'option1'
},
2: {
options: 'option2'
},
3: {
options: 'option3'
}
}
} */
}
const specificData = data.attributes.items[3].options
console.log(specificData) //
So one solution would be using the optional chaining operator to avoid the error, it's just basically a question mark (?) after the object you are trying to access.
The response would be then 'undefined'. That way even if the attributes is empty or not, data will be assigned to the response constant then you can just add some more checking outside of that.
// sample
const data = {
/* attributes: {
items: {
1: {
options: 'option1'
},
2: {
options: 'option2'
},
3: {
options: 'option3'
}
}
} */
}
const specificData = data.attributes?.items[3].options
console.log(specificData) // outputs undefined instead of an error
Let me know if this works btw. maybe you could provide the actual api or maybe a sample api endpoint so we could test it directly. Or maybe the full code?
I've encoutered this before though I'm not 100% sure this is all I've done. But for the error I'm sure the optional chaining operator will prevent it
Try calling getData inside an async function and wait for the process to complete like this in your App.js
const [data, setData] = useState([]);
const [roomCount, setRoomCount] = useState([]);
useEffect(() => {
getDataFunc()
}, []);
const getDataFunc = async() => {
await getData(setData);
const response = data;
console.log(response);
const entries = Object.entries(response);
const tempArray = [];
for (let i = 0; i < entries.length; i++) {
var key;
var value;
(key = entries[i][0]), (value = entries[i][1]);
tempArray.push({ key: value, value: key });
}
setRoomCount(tempArray);
console.log(roomCount);
}
note: The best practice is not to directly pass the setData function to getData api call instead return the response from api and assign the response in main code like below
const response = await getData();
setData(response)
From what I see, your data.attributes has undefined value.
Please double-check everything, it is technically impossible to get data directly if data.attributes is undefined

How to inject string into api response in react native?

I have an array of objects response that comes from API. I don't have access to the API to be able to change it.
data = [
{"label": "Group 1", "value": "1"},
{"label": "Group 2", "value": "2"},
{"label": "Group 3", "value": "3"}
]
I need to display the data, so the label says Post to ${label}.
Can I inject the 'Post to ' string somehow? Do I make a new array from my response?
Here's how I'm fetching the data:
const [pickerData, setPickerData] = React.useState<{ label: string; value: string }[]>([]);
const fetchPickerData = React.useCallback(async () => {
const response = await getPostLocations();
if (!response) return;
if (response) {
setPickerData(response);
}
}, []);
React.useEffect(() => {
fetchPickerData().catch(console.error);
}, [fetchPickerData]);```
and my data is then loaded into a picker:
<Picker
items={pickerData}
value={pickerItem}
onValueChange={(pickerItem) => setPickerItem(pickerItem)}
/>
Things I already tried is trying to inject string into value like value={()=>{`Post to ${pickerItem}`}}, or the same in the setPickerItem in onValueChange but that didn't work
You can use Array#map() to create a new array from the response in the format you prefer:
const fetchPickerData = React.useCallback(async () => {
const response = await getPostLocations();
if (!response) return;
if (response) {
const formattedResponse = response.map(
({ label, value }) => ({ 'label': `Post to ${label}`, value })
)
setPickerData(formattedResponse);
}
}, []);
Try it like this
const [pickerData, setPickerData] = React.useState<{ label: string; value: string }[]>([]);
const [apiData, setApiData] = React.useState<{ label: string; value: string }[]>([]);
const fetchPickerData = React.useCallback(async () => {
const response = await getPostLocations();
if (!response) return;
if (response) {
setApiData(response);
}
}, []);
React.useEffect(() => {
fetchPickerData().catch(console.error);
}, [fetchPickerData]);
React.useEffect(() => {
if (apiData.length > 0) {
let Temp = [];
apiData.forEach((item) => {
let newItem = {
...item,
label: `Post to ${item.label}`
};
Temp.push(newItem);
});
setPickerData(Temp);
}
}, [apiData]);

Pushing data to an array in already existing object with axios

i have a object which looks like this:
{
"title": "675756",
"release_date": "2022-01-16",
"series": "Better Call Saul",
"img": "https://upload.wikimedia.org/wikipedia/en/0/03/Walter_White_S5B.png",
"characters": [],
"id": 1
}
to an characters array i want to add the id of characters.
I do it by form and then i handle submit like this:
const handleSubmit = (values) => {
console.log("dodano aktora do filmu!");
console.log(values);
addActorToMovie(values);
history.goBack();
};
the addActorToMovie action:
export const addActorToMovie = (resp) => ({
type: types.ADD_CHAR_TO_MOVIE,
payload: resp,
});
and the reducer:
case types.ADD_CHAR_TO_MOVIE:
console.log(action.payload);
return {
...state,
...state.episodes.map(function (item) {
return item.id === action.payload.episodeId
? {
id: item.id,
title: item.title,
release_date: item.release_date,
series: item.series,
img: item.img,
characters: [...item.characters, action.payload.actor],
}
: { ...item };
}),
};
It all works, but the problem is that i dont want to do it loccaly. Im using an database with json-server, and I want to do an Axios Request so that it would add a data to the database.
And i don't know how to do this, when i use axios.post it adds an object to my episodes array, if im using axios.put it changes an object. Is there any possibility to push the data to an array as i do it with the code above, but with axios so that it would be added to database?
My approach looked like this:
export const addActorToMovieAxios = (value) => {
console.log(value);
return async (dispatch) => {
try {
const response = await axios.post(
`http://localhost:3000/episodes/`,
value
);
console.log(response);
dispatch(addActorToMovie(response.data));
} catch (ex) {
console.log(ex);
}
};
};
but as I said this does add a new object to an array.....
"episodes": [
{
"title": "675756",
"release_date": "2022-01-16",
"series": "Better Call Saul",
"img": "https://upload.wikimedia.org/wikipedia/en/0/03/Walter_White_S5B.png",
"characters": [],
"id": 1
},
{
"episodeId": 1,
"actor": "1",
"id": 2
}
]
So just to be clear I understand your question, you have an object that already exists in your DB, and you want to push something onto the 'characters' array in that existing object, without creating a new object, correct?
To do this, I would use Mongo for your DB and define two Mongoose Schemas, one for the existing object (let's call it TVShow) and one for the Characters within that object. Your two Schemas will look like this:
TVShowModel.js:
const mongoose = require('mongoose');
const CharacterModel = require('./CharacterModel')
const TVShowScheme = new mongoose.Schema({
title: {
type: String,
},
release_date: {
type: Date,
},
series: {
type: String,
},
img: {
type: String,
},
characters:[
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Student'
},
],
examQuestions: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'CharacterModel'
}
]
})
module.exports = mongoose.model('TVShowModel', TVShowScheme )
CharacterModel.js:
const mongoose = require('mongoose');
const CharacterModel= new mongoose.Schema({
characterName: {
type: String,
},
actorName: {
type: String,
},
}) // add any other fields you want here
module.exports = mongoose.model('CharacterModel', CharactModelScheme )
Then, create your Axios post request. Make sure you send when you send the 'value' variable to your server, it contains the id (or perhaps the unique title) of the object you'll be 'pushing' to. Push won't work in axios/react, so we'll use the 'spread' opperator instead.
Your router will look like this:
const CharacterModel= require ('../models/CharacterModel');
const TVShowModel= require ('../models/TVShowModel');
const router = express.Router();
router.post('/episodes', async function(req,res){
try{
const tvshow = await TVShowModel.find({title: req.body.title})
// edit as needed
console.log("FOUND TV Show: "+tvshow )
const characterName= req.body.characterName
const actorName = req.body.actorName
const newCharacter = new CharacterModel({
characterName,
actorName,
})
console.log("new character created: "+newCharacter)
tvshow[0].CharacterModel = [...tvshow[0].CharacterModel,newCharacter];
await tvshow[0].save()
.then(()=>res.json('New Character Added to DB'))
.catch(err=>res.status(400).json('Error: ' + err))
} catch(e){
console.log(e)
}
})
Hope this was clear!

Connecting 2 different arrays from the same external link - React hooks fetch

I am able to fetch data what url, but the thing is the url is divided into couple of arrays and I need to fetch data and connect them.
Example:
{
"array1": [
{ "data1": {"name": "Name", "phone": "Phone"}}
]
"array2" : [
{ "data2": { "color": "Color", "car": "Car" } }
]
}
Data hooks :
const userInfo = "URL";
const [userData, setUserData] = useState([]);
useEffect(() => {
getUserInfo();
}, []);
const getUserInfo = async () => {
const response = await fetch(UserInfo);
const jsonData = await response.json();
setUserData(jsonData);
};
Fetch data:
{ userData.data && userData.array1.map((array1, index) =>
<li key={"index" + index}
<h5>{array1.data1.name} </h5>
</li>
)}
I need to connect name from array1 with color from array2, but I can not find the way to do it.
Expected Output : list of data
If you can get those two arrays then you can use this to combine them:
const getUserInfo = async () => {
const response = await fetch(UserInfo);
const jsonData = await response.json();
// this assumes `jsonData` in an object with keys `array1` and `array2`
// if this is not the case, change `jsonData` below to the location of
// those two arrays
const { array1, array2 } = jsonData;
const combinedArray = array1.map(({ data1 }, i) => ({
...data1,
...array2[i].data2 // assumes there is always a corresponding index in array 2
}));
// combinedArray will look like [ { name: 'Name', phone: 'Phone', color: 'Color', car: 'Car' } ] 
setUserData(combinedArray);
};
] 

Get request using loop

There was such a problem.
I'm trying to make a certain number of GET requests in Wikipedia API using a cycle.
Trying to do this with the function getAllInfo()
articles.components.ts
export class ArticlesComponent {
constructor(private articlesServices: ArticlesService) { }
#Input() allTitles: string[];
articlesInfo: ArticleInformationNew;
allArray: [[string, number]] = [['', 0]];
static getUrlInformation(searchQuery: string) {
return 'https://ru.wikipedia.org/w/api.php?action=query&titles='
+ searchQuery + '&prop=info&format=json&origin=*';
}
getAllInfo() {
for (const title of this.allTitles) {
this.articlesServices.getArticleInformation(ArticlesComponent.getUrlInformation(title))
.subscribe(
(data: ArticleInformation) => this.articlesInfo = {
...data,
query: { pages: [Object.values(data.query.pages)[0]]}}
);
this.allArray.push([this.articlesInfo.query.pages[0].touched, this.articlesInfo.query.pages[0].length]);
}
}
}
articles.service.ts
export interface ArticleInformation {
batchComplete: string;
query: {
pages: {
}
};
}
export interface ArticleInformationNew {
batchComplete: string;
query: {
pages: any[]
};
}
export class ArticlesService {
constructor(private http: HttpClient) { }
getArticleInformation(url) {
return this.http.get<ArticleInformation>(url);
}
}
An array this.allTitles can consist of a number of lines. For example: this.allTitles = ['Naumen', 'Naumen DMS']
I expect that the arraythis.allArray will be two-dimensional and contain arrays that consist of rows with data for each query. For example:
this.allArray[0] = ['', 0]
this.allArray[1] = ['2019-02-01T23:27:26Z', 3687]
this.allArray[2] = ['2019-01-21T04:24:21Z', 9704]
But in fact, it turns out that each element of a two-dimensional array is the same. For example:
this.allArray[0] = ['', 0]
this.allArray[1] = ['2019-02-01T23:27:26Z', 3687]
this.allArray[2] = ['2019-02-01T23:27:26Z', 3687]
Why and how to fix it?
Try this,
getAllInfo() {
for (const title of this.allTitles) {
this.articlesServices.getArticleInformation(ArticlesComponent.getUrlInformation(title))
.subscribe(
(data: ArticleInformation) => {
this.articlesInfo = {
...data,
query: { pages: [Object.values(data.query.pages)[0]]}
}
this.allArray.push([this.articlesInfo.query.pages[0].touched,this.articlesInfo.query.pages[0].length]);
}
);
}
}
You can use combineLatest: https://www.learnrxjs.io/operators/combination/combinelatest.html
First, collect observables to be combined (but without subscribing to them), then combine them with combineLatest and get the response as an array and iterate over it.
getAllInfo() {
console.log(this.allTitles);
observablesToSubscribe = [];
for (const title of this.allTitles) {
observablesToSubscribe.push(this.articlesServices.getArticleInformation(ArticlesComponent.getUrlInformation(title)));
}
combineLatest(observablesToSubscribe).subscribe((responseData: Array<ArticleInformation>) => {
responseData.forEach((responseDatum) => {
this.allArray.push({
...data,
query: { pages: [Object.values(data.query.pages)[0]]}
})
});
});
}
Maybe, I misunderstood the question, but you can get pages with particular titles, by correcting your searchQuery (using alternative separators for titles), and get rid of for loop:
getAllInfo() {
console.log(this.allTitles);
this.articlesServices.getArticleInformation(
ArticlesComponent.getUrlInformation(this.allTitles.join('|'))
.subscribe(
(res => {
// here is a result with all pages of particular titles,
// then you can process your result...
console.log(res);
// this.allArray is a multidimensional array
// [["2019-01-25T00:45:06Z",4508],
// ["2019-01-26T07:25:08Z", 773]]
this.allArray = Object.keys(res.query.pages)
.reduce((acc, val, index) => {
acc[index] = [pages[val].touched, pages[val].length];
return acc;
}, []);
});
}
searchQuery for titles will be in that case Naumen | Naumen DMS (not, for example, just Naumen). | (pipe) is an alternative separator for titles.
To process the result (res.query.pages):
const pages = {
"755288": {
"pageid": 755288,
"ns": 0,
"title": "Spring",
"contentmodel": "wikitext",
"pagelanguage": "ru",
"pagelanguagehtmlcode": "ru",
"pagelanguagedir": "ltr",
"touched": "2019-01-26T07:25:08Z",
"lastrevid": 84434967,
"length": 773
},
"92586": {
"pageid": 92586,
"ns": 0,
"title": "Atom",
"contentmodel": "wikitext",
"pagelanguage": "ru",
"pagelanguagehtmlcode": "ru",
"pagelanguagedir": "ltr",
"touched": "2019-01-25T00:45:06Z",
"lastrevid": 95248014,
"length": 4508
},
};
const arr = Object.keys(pages).reduce((acc, val, index) => {
acc[index] = [pages[val].touched, pages[val].length];
return acc;
}, []);
console.log(arr);

Resources