as you see the code, on the handleUpdateFilter function the second "if" some how defaultCourseData is filtered as filteredData of the first "if". Thank you for helping me!
setup() {
const course = ref();
const defaultCourseData = null
const gettingCourse = async () => {
const { data } = await getCourse();
defaultCourseData = data
course.value = data;
};
const handleUpdateFilter = (data) => {
// data is filtering value
if (data.value.view) {
const filteredData = defaultCourseData.sort((a, b) => b.luotXem - a.luotXem);
course.value = filteredData;
}
if (!data.value.view) {
course.value = defaultCourseData // This case some how defaultCourseData filtered too
}
};
onMounted(() => {
gettingCourse();
});
return {
course,
handleUpdateFilter,
defaultCourseData
};
},
Your defaultCourseData variable isn't reactive.
Therefore it should be evaluated as null at every call.
Try this
defineComponent({
setup() {
const course = ref([]);
const defaultCourseData = ref([]);
const gettingCourse = async () => {
const { data } = await getCourse();
defaultCourseData.value = data
course.value = data;
};
const handleUpdateFilter = (data) => {
// data is filtering value
if (data.value.view) {
course.value = defaultCourseData.value.sort((a, b) => b.luotXem - a.luotXem);
}
if (!data.value.view) {
course.value = defaultCourseData.value // This case some how defaultCourseData filtered too
}
};
onMounted(async () => {
await gettingCourse();
});
return {
course,
handleUpdateFilter,
defaultCourseData
};
})
Edit: The actual issue here was, that the defaultCourseData always returned a sorted array as Array.prototype.sort() mutates the Array.
So making a copy solves the issue.
if (data.value.view) { course.value = [...defaultCourseData.value].sort((a, b) => b.luotXem - a.luotXem); }
Related
in my application, there are two types of filters, category and country. However, I am not able to get them to be applied at the same time. For example, I only want the intersection of Category: SaaS + Country: Singapore.
Any advice?
const loadData = props.load
const [card, setCard] = useState(loadData)
const [searchPhrase, setSearchPhrase] = useState("")
const search = (event)=>{
const matchedUsers = loadData.filter((card)=>{
return card.title.toLowerCase().includes(event.target.value.toLowerCase())
})
setCard(matchedUsers)
setSearchPhrase(event.target.value)
}
const filterCountry = (event)=>{
const filteredCards = loadData.filter((card)=>{
return card.country.includes(event.target.value)
})
setCard(filteredCards)
}
const filterCat = (event)=>{
const filteredCards = loadData.filter((card)=>{
return card.cat.includes(event.target.value)
})
setCard(filteredCards)
}
You can change your filter condition to check if the value is in all your considered types
const result = yourData.filter(item => item.country.includes(YOURPHRASE) || item.cat.includes(YOURPHRASE))
you can pass the filtered array as a parameter to the filtering functions :
const search = (event)=>{
const matchedUsers = loadData.filter((card)=>{
return card.title.toLowerCase().includes(event.target.value.toLowerCase())
})
setSearchPhrase(event.target.value);
return matchedUsers
}
const filterCountry = (event,array)=>{
return array.filter((card) => card.country.includes(event.target.value);
}
const filterCat = (event,array)=>{
return array.filter((card) => card.cat.includes(event.target.value);
}
useEffect(() => {
let result = matchedUsers();
result = filterCountry(result);
result = filterCat(result);
setArrayToFilter(result);
}, [searchPhrase]);
I have listend an event in customhook and when that event works, I have to do some logic there with state.but now I only get empty array every time that event callback works.
const useChatHistoryList = () => {
const sk = useSocket();
const [chatList, setChatList] = useState([]);
const [end, setEnd] = useState(true);
useEffect(() => {
sk.emit('chatlist');
}, [start]);
useEffect(() => {
const onChatListReceived = data => {
const _data = JSON.parse(data);
setHistoryLoading(false);
setChatList(_data);
};
const onChatListToUpdateReceived = data => {
const _data = JSON.parse(data);
console.log(chatList);//getting only empty array everytime
};
sk.on('chatlist', onChatListReceived);
sk.on('chatlistToUpdate', onChatListToUpdateReceived);
return () => {
sk.off('chatlistToUpdate');
sk.off('chatlist');
};
}, []);
return { chatList,end};
};
Try to log your data first to make sure the data is there, then set your state with the data.
const [state, setState]= useState([]);
const _onReceived = (data) => {
// Here is your data from socket
console.log(data);
// Then set state value with data
setState(data);
}
useEffect(()=>{
// Init socket listener
socket.on("event", _onReceived);
}, []);
// This effect will runs everytime state value is set (including when setting default value)
useEffect(()=>{
// Actual 'state' value
console.log('State value: ', state);
}, [state]);
==========================
Edit, related to your updated codes in the question
Your onChatListToUpdateReceived function brings empty default value to the listener even later when it’s updated, your listener will still recognize chatList value as an empty string. Try to move out onChatListToUpdateReceived outside useEffect.
const onChatListToUpdateReceived = data => {
const _data = JSON.parse(data);
console.log(chatList);//getting only empty array everytime
};
useEffect(() => {
const onChatListReceived = data => {
const _data = JSON.parse(data);
setHistoryLoading(false);
setChatList(_data);
};
sk.on('chatlistToUpdate', onChatListToUpdateReceived);
return () => {
sk.off('chatlistToUpdate');
sk.off('chatlist');
};
}, []);
useEffect(() => {
sk.off('chatlistToUpdate');
sk.on('chatlist', onChatListReceived);
}, [chatList]);
I have not used socket.io before but this is what I meant by asynchronous update. From your code, it looked to me like your callback is getting called before the state is updated. So to solve this, I added a useEffect() with chatList as a dependency so that callback gets called every time chatList gets updated. I hope this makes sense.
const useChatHistoryList = () => {
const sk = useSocket();
const [chatList, setChatList] = useState([]);
const [end, setEnd] = useState(true);
const onChatListReceived = data => {
const _data = JSON.parse(data);
setHistoryLoading(false);
setChatList(_data);
};
const onChatListToUpdateReceived = data => {
const _data = JSON.parse(data);
console.log(chatList); //getting only empty array everytime
};
useEffect(() => {
sk.on('chatlist', onChatListReceived);
sk.on('chatlistToUpdate', onChatListToUpdateReceived);
return () => {
sk.off('chatlistToUpdate');
sk.off('chatlist');
};
}, []);
// Emit chatlistToUpdate whenever chatList is updated
useEffect(() => {
sk.emit('chatlistToUpdate');
}, [chatList]);
return {
chatList,
end
};
};
I'm trying to understand behavior of function based composition in JavaScript.
const Animal = (name) => {
let properties = { name };
return ({
get name() { return properties.name },
set name(newName) { properties.name = newName },
breathe: function() {console.log(`${this.name} breathes!`); }
})
}
const aquaticKind = (animal) => ({
swim: () => console.log(`${animal.name} swims`)
})
const walkingKind = (animal, noOfLegs) => {
const properties = { noOfLegs }
return ({
get noOfLegs() { return properties.noOfLegs },
set noOfLegs(n) { properties.noOfLegs = n; },
walk: () => console.log(`${animal.name} walks with ${properties.noOfLegs} legs`)
})
}
const egglayingKind = (animal) => ({
layEgg: () => console.log(`${animal.name} laid an egg`)
})
const Crocodile = (name) => {
const info = Animal(name);
return Object.assign(info,
walkingKind(info, 4),
aquaticKind(info),
egglayingKind(info)
);
}
const snooty = Crocodile('snooty');
snooty.breathe();
snooty.swim();
snooty.walk();
snooty.name = "coolie";
snooty.noOfLegs = 23 // I expected this to get update to 23
snooty.swim();
snooty.walk();
snooty.layEgg();
If you run the code above, you will see that noOfLegs never get updated, while name get updated. I can't seem to wrap my head around this. How do we make noOfLegs get updated too?
MDN Documentation for object.assign shows you how to copy "accessors"
Here's your code that works as expected - the completeAssign function is based entirely on the code in that link
const completeAssign = (target, ...sources) => {
sources.forEach(source => {
const descriptors = Object.keys(source).reduce((descriptors, key) => {
descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
return descriptors;
}, {});
Object.getOwnPropertySymbols(source).forEach(sym => {
const descriptor = Object.getOwnPropertyDescriptor(source, sym);
if (descriptor.enumerable) {
descriptors[sym] = descriptor;
}
});
Object.defineProperties(target, descriptors);
});
return target;
};
const Animal = (name) => {
const properties = { name };
return ({
get name() { return properties.name },
set name(newName) { properties.name = newName },
breathe () { console.log(`${this.name} breathes!`); }
})
}
const aquaticKind = (animal) => ({
swim: () => console.log(`${animal.name} swims`)
});
const walkingKind = (animal, noOfLegs) => {
const properties = { noOfLegs };
return ({
get noOfLegs() { return properties.noOfLegs },
set noOfLegs(n) { properties.noOfLegs = n; },
walk: () => console.log(`${animal.name} walks with ${properties.noOfLegs} legs`)
})
}
const egglayingKind = (animal) => ({
layEgg: () => console.log(`${animal.name} laid an egg`)
})
const Crocodile = (name) => {
const info = Animal(name);
return completeAssign(info,
walkingKind(info, 4),
aquaticKind(info),
egglayingKind(info)
);
}
const snooty = Crocodile('snooty');
snooty.breathe();
snooty.swim();
snooty.walk();
snooty.name = "coolie";
snooty.noOfLegs = 23;
snooty.swim();
snooty.walk();
snooty.layEgg();
I have API query and getting the result and setting those in a state variable in Oncompleted method of API query, Now i am updating the same state variable in another api query "onCompleted method.
I am not able to access the result from state what i have set before in first api query and below is my code
Query 1:
const designHubQueryOnCompleted = designHubProject => {
if (designHubProject) {
const {
name,
spaceTypes
} = designHubProject;
updateState(draft => { // setting state here
draft.projectName = name;
draft.spaceTypes = (spaceTypes || []).map(po => {
const obj = getTargetObject(po);
return {
id: po.id,
name: obj.name,
category: obj.librarySpaceTypeCategory?.name,
description: obj.description,
warning: null // trying to modify this variable result in another query
};
});
});
}
};
const { projectDataLoading, projectDataError } = useProjectDataQuery(
projectNumber,
DESIGNHUB_PROJECT_SPACE_TYPES_MIN,
({ designHubProjects }) => designHubQueryOnCompleted(designHubProjects[0])
);
Query 2:
const {
// data: designhubProjectSpaceTypeWarnings,
loading: designhubProjectSpaceTypeWarningsLoading,
error: designhubProjectSpaceTypeWarningsError
} = useQuery(DESIGNHUB_PROJECT_LINKED_SPACETYPE_WARNINGS, {
variables: {
where: {
projectNumber: { eq: projectNumber }
}
},
onCompleted: data => {
const projectSpaceTypeWarnings = data.designHubProjectLinkedSpaceTypeWarnings[0];
const warnings = projectSpaceTypeWarnings.spaceTypeWarnings.reduce((acc, item) => {
const spaceTypeIdWithWarningState = {
spaceTypeId: item.spaceTypeProjectObjectId,
isInWarningState: item.isInWarningState
};
acc.push(spaceTypeIdWithWarningState);
return acc;
}, []);
console.log(state.spaceTypes); // trying to access the state here but getting empty array
if (state.spaceTypes.length > 0) {
const updatedSpaceTypes = state.spaceTypes;
updatedSpaceTypes.forEach(item => {
const spaceTypeWarning = { ...item };
spaceTypeWarning.warning = warnings?.filter(
w => w.spaceTypeId === spaceTypeWarning.id
).isInWarningState;
return spaceTypeWarning;
});
updateState(draft => {
draft.spaceTypes = updatedSpaceTypes;
});
}
}
});
Could any one please let me know where I am doing wrong with above code Or any other approach to modify the state, Many thanks in advance!!
I want to get data from the database. Then change them. And then display.
Please tell me how to solve this problem and why I can not do it.
Here is my code
let firebaseConfig = {...};
firebase.initializeApp(firebaseConfig);
let ref = firebase.database().ref('/data')
class DataTable {
constructor(parent) {
this.parent = parent;
}
buildTable(data) {
this.data = data;
const keys = Object.keys(data[0]);
console.log(keys)
let div = document.createElement('div');
let tab = document.createElement('table');
let tb = document.createElement('tbody');
const buildTableBody = () => {
for (let a of data) {
let tr = document.createElement('tr');
keys.forEach((key) => {
let td = document.createElement('td');
let tn = document.createTextNode(a[key])
td.appendChild(tn);
tr.appendChild(td);
});
tb.appendChild(tr);
}
tab.appendChild(tb);
div.appendChild(tab);
}
this.parent.appendChild(div);
buildTableBody()
}
}
const table = new DataTable(document.body);
table.buildTable(
ref.once("value").then((snap) => {
const data = snap.val()
data.map(i => {
let res = {
'#': Number(i.id),
'Name': i.name,
};
return Object.entries(res).reduce((memo, [key, value]) => {
if (value) {
return {
...memo,
[key]: value
}
} else {
return memo;
}
}, {})
})
}))
But it returns to me Promise {}proto: Promise[[PromiseStatus]]: "resolved"[[PromiseValue]]: undefined
The way you're trying to pass the data into buildTable doesn't work. If you put a breakpoint inside buildTable, you'll be able to see that.
The reason is that the data is loaded from Firebase asynchronously, and any code that needs the data has to be called from inside the once() callback. So you'll want to put the call to buildTable within that callback, like this:
ref.once("value").then((snap) => {
const data = snap.val()
let result = data.map(i => {
let res = {
'#': Number(i.id),
'Name': i.name,
};
return Object.entries(res).reduce((memo, [key, value]) => {
if (value) {
return {
...memo,
[key]: value
}
} else {
return memo;
}
}, {})
})
table.buildTable(result);
}))