I have a CRUD functionality in my react application using hooks and es6.
I'm using AntDesign List Component as well. In my add function, after adding for the first time, it's expected that it's been added on the list.
But after creating another one, it's just replacing the existing array. It's not been added like index 1. It's always index 0.
Here's my code
const leaveTypeList = [];
const [isLeaveType, setLeaveType] = useState(leaveTypeList);
useEffect(() => {
setLeaveType(leaveTypeList);
}, [setLeaveType]);
const payload = {
leaveTag: values.leaveTag,
leaveTagColor: values.leaveTagColor,
hexCode: state.tagColor,
dateCreated: formatLeaveTypeDate,
};
leaveTypeList.push(payload);
setLeaveType(leaveTypeList);
hey since you need to add a new item to array there is no need of the useEffect hook
const leaveTypeList = [];
const [isLeaveType, setLeaveType] = useState(leaveTypeList);
const payload = {
leaveTag: values.leaveTag,
leaveTagColor: values.leaveTagColor,
hexCode: state.tagColor,
dateCreated: formatLeaveTypeDate,
};
setLeaveType([...isLeaveType,payload]);
you can simple use setter to set new state updating the existing array by adding the new payload to it.
You should push the new data by isLeaveType.push(payload).
Also,
useEffect(() => {
setLeaveType(leaveTypeList);
}, [setLeaveType]);
makes no sense to me.
Since the setLeaveType is the setter for isLeaveType, there is no reason for the effect to depend on it.
Related
I'm developing a quiz/test website. I want to see different questions when I move to next question and don't want to see same answers at the same time.
I have a state array varaible which is calling allWords. This state
will keep all words.
And I have another state array variable which calls like
neverAskedWords. This state will keep words which never used
always.
I'm creating a new array variable and defining with allWords in a function. When I'm removing any record in the new array variable then that record is removing in allWords variable as well... Why?
I want to remove any record in that temporary array and want to save updated version to neverAskedWords state. In this way I could see different questions always. Here is my codes.
const [allWords, setAllWords] = useState([])
const [neverAskedWords, setNeverAskedWords] = useState([])
async function getAllData(){
axios
.get(`http://127.0.0.1:3000/api/improve-language`)
.then(res => {
setAllWords(res.data)//defining allWords
setNeverAskedWords(res.data)//defining neverAskedWords
firstQuestionAndAnswers(res.data)//sending all datas by parameter, bacause when I'm trying to get datas by using `allWords` state, it would be undefined. That's why sending all data by parameter for the first time to set first question and answers.
})
.catch(err =>{
console.log(err)
})
}
async function firstQuestionAndAnswers(wordsList){
let neverAskedList = await wordsList //creating and defining temporary variables
const allWordsList = await wordsList //creating and defining temporary variables
//some not necessary codes for this issue
const questionIndex = randomNumber(neverAskedList.length)
const firstQuestion = neverAskedList[questionIndex]
let firstAnswers = []
for (let i = 0; i < 4; i++) {
let answerIndex = randomNumber(allWordsList.length)
firstAnswers[i] = allWordsList[answerIndex]
allWordsList.splice(answerIndex, 1)//and here! I'm removing this record to prevent using it again next time, there will be different answers always
}
//some not necessary codes for this issue
firstAnswers.push(firstQuestion)
const randomisedAnswers = firstAnswers.sort(()=>Math.random() - 0.5)
//some not necessary codes for this issue
setQuestion(firstQuestion)
setAnswers(randomisedAnswers)
//and then here! I'm removing the used question in this time to prevent using it again, there will be different questions always and never see this question again
neverAskedList.splice(questionIndex, 1)
setNeverAskedWords(neverAskedList)
}
allWords should'nt change. But changing, because of why?
So the most obvious thing that I see in your code is that you are modifying the same object. What you should do instead is use the spread operator.
const [allWords, setAllWords] = useState([])
const [neverAskedWords, setNeverAskedWords] = useState([])
async function getAllData(){
axios
.get(`http://127.0.0.1:3000/api/improve-language`)
.then(res => {
setAllWords(res.data)//defining allWords
setNeverAskedWords(res.data)//defining neverAskedWords
firstQuestionAndAnswers(res.data)//sending all datas by parameter, bacause when I'm trying to get datas by using `allWords` state, it would be undefined. That's why sending all data by parameter for the first time to set first question and answers.
})
.catch(err =>{
console.log(err)
})
}
async function firstQuestionAndAnswers(wordsList){
// don't use await for js objects, should be used only with promises.
// use spread operator to make copy of the wordList array so you never actually modify the original object
let neverAskedList = [...wordsList]
const allWordsList = [...wordsList]
//some not necessary codes for this issue
const questionIndex = randomNumber(neverAskedList.length)
const firstQuestion = neverAskedList[questionIndex]
let firstAnswers = []
for (let i = 0; i < 4; i++) {
let answerIndex = randomNumber(allWordsList.length)
firstAnswers[i] = allWordsList[answerIndex]
allWordsList.splice(answerIndex, 1)//and here! I'm removing this record to prevent using it again next time, there will be different answers always
}
//some not necessary codes for this issue
firstAnswers.push(firstQuestion)
const randomisedAnswers = firstAnswers.sort(()=>Math.random() - 0.5)
//some not necessary codes for this issue
setQuestion(firstQuestion)
setAnswers(randomisedAnswers)
//and then here! I'm removing the used question in this time to prevent using it again, there will be different questions always and never see this question again
neverAskedList.splice(questionIndex, 1)
setNeverAskedWords(neverAskedList)
}
If you don't understand why it happened then here's a short explanation. In js when you do const a = { key: 'val' } you created a variable that references the memory block that is actually storing your object. And when you do const b = a you are creating another variable that references the same memory block. So updating 1 automatically changes the other one.
Within my function, through interaction from the user, I aim slowly build up an array of responses which I then pass off to an API. However, different approaches to append to the array, simply return a single position array (overwrite).
My current code as follows:
const contribution: Array = [];
const handlePress = () => {
var col = {
response,
user: 1,
update: update.id,
question: q.id,
};
contribution = [...contribution, col];
}
My understanding is that contribution = [...contribution, col] is the correct way to add to the array.
What is the best practice approach for doing this inside a function called each time the user interacts?
Although it is not clear from the question, I suspect, this code is inside a component. If so, then a new contribution array is created on every render. You need to use useState to store this array so that a new array is not created on every render.
const [contribution, setContribution] = React.useState([]);
const handlePress = () => {
var col = {
response,
user: 1,
update: update.id,
question: q.id,
};
setContribution([...contribution, col]);
}
I have a form that dynamically enters elements to a react state array on click, and obviously between clicks the state persists. I am trying to now do the same thing programatically but in each iteration the state does not persist, is the only answer to this truly a context object or local storage or is there something wrong with my iteration that I can correct to allow state to persist.
Ive simplified the code basically the button firing will add as many elements as I want but trying to tell react to create 3 elements via the for const only creates 1. I have scripts to write state to session storage, so if there's not some big thing i'm missing, I'll probably just do that, but i figure I'd ask and see cause it would drastically improve the overall health of my app if i knew the solution to this.
const sectionI = {
type: "i",
sectionArea: "",
};
const [i, setI] = useState([])
const strArr = ["i","i","i"]
const addI = () =>{
const newI = [...i, {...sectionI}]
setI(newI)
}
<button onClick={()=>addI()}>Add One Image</button>
const addMultiple = () =>{
for(const el of strArr){
const newI = [...i, {...sectionI}]
setI(newI)
}
}
I will show you how to fix it and give you a link to another one of my answers for the explanation. Here is how to fix the issue:
const addMultiple = () =>{
for(const el of strArr){
setI(prevState => [
...prevState,
{...sectionI},
])
}
}
And here is why it is happening: https://stackoverflow.com/a/66560223/1927991
My object is create an array of object as follows [{},{},{}]
State variable constructor like this:
this.state:{...some states,
parsed:[{}]}
Every object come from get IPFS with async function:
IPFSREADER = element => {
ipfs.cat(convertedIPFSaddress).then(result => {
let cons = result.toString('utf8')
const consdata = JSON.parse(cons);
// NEED useState save consdata to parsed state
}
When I get data, I am pushing this data to state with useState, but I tried as follows way:
this.setState({parsed:consdata}) result: > Object:{some data...}
this.setState({...[parsed],parsed:[consdata]}) result: [0:Object:{some data...}]
When there is a new data coming from ipfs, this only changes data, where is into the array, but doesn't append to tail of previous data.
this.setState(parsed => [...data, parsed]); follow Joseph D.'s answer, but throw ReferenceError: can't access lexical declaration 'data' before initialization error. Try this solution changed above function as follows:
changed the function to async: IPFSREADER = async element => {..
added await in front of ipfs.cat: const { data } = await ipfs.cat(...
How can solve this problem? I tried many solutions, but can't change the result... Thanks.
It looks like you are trying to do setState({...state, parsed: [...state.parsed, consdata]})
//It's working now - updated code
I'm working on my own autocomplete component because I have problem with passing firebase data to a ready one.
The whole mechanism is working good but I have problem with passing values after getting user input
I'm setting initial state with those values
const INITIAL_STATE = {
allChars: [],
suggestions: [],
value: ""
};
Then in autocomplete class i'm loading all users from database
loadData(){
let self = this;
let characters = firebase.firestore().collection("users");
characters.get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
let document = doc.data();
self.setState(({allChars})=>({
allChars: [
...allChars,
document
]
}))
});
});
}
Here is my getSuggestions function. It is firing on input change
getSuggestions = event => {
const {value, suggestions} = event.target;
this.setState({
value: value,
suggestions: []
})
let suggest = [];
this.state.allChars.map((allChars) => {
if(value.length > 1 && allChars.name.toLowerCase().includes(value.toLowerCase())){
suggest.push (
allChars.name
);
}
})
this.setState({
suggestions: suggest
})
}
In render I just put {sugestions}
But in {suggestions} I get rendered only one name.
one
But when I console.log it - I get two names
two
There should be two.
I tried to set state in this function like in loadData(), but I still get only one value.
Is there other way to get both values into DOM
Full code can be found here: https://github.com/Ilierette/react-planner/blob/master/src/component/elements/Autocomplete.js
I think the reason you are just seeing one element each time your components re-render is that in your map function on your allChars array, when you want to update the suggestions in your state, you are setting just the name each time as a new array while you should update the existing array in your state, so your code should be:
this.setState({
suggestions: [...this.state.suggestions, allChars.name]
})