ReactJS: querySelectorAll .map function not working as expected with State - reactjs

I am trying to push my querySelectorAll .map function to a React State Array but its not working as expected.
const [affectedServices, setAffectedServices] = useState([]);
function affectedTags() {
Array.from(document.querySelectorAll(".active-tag")).map((tag) => {
console.log(tag.innerHTML);
setAffectedServices([tag.innerHTML]);
});
}
console.log(tag.innerHTML) will display all querySelected tags e.g.
Active tag 1
Active tag 2
Active tag 3
But when viewing the affectedServices state from React Dev tools, it only has one array which contains Active tag 3
Any ideas of what im doing wrong?
TIA

Try like this.
I think I will works for you.
const [affectedServices, setAffectedServices] = useState([]);
function affectedTags() {
setAffectedServices(Array.from(document.querySelectorAll(".active-tag")).map((tag) => {return tag.innerHTML})));
}

you need to push the value in the array at every loop, and not just replacing the previous value by a new, can you try this ?
useEffect(() => {
console.log("affectedServices ", affectedServices);
}, [affectedServices]);
function affectedTags() {
let result = [];
Array.from(document.querySelectorAll(".active-tag")).forEach((el) => {
result.push(el);
});
setAffectedServices(result);
}

Related

React Native add to state array if value does not exist

I would like to know the best way to add a value to an array of the value does not exist in my state variable. The current code works but I a newbie and not sure if I am doing this correctly. This function is fired when a button is pressed
const App = () => {
const [answered, setAnswered] = useState([])
const handleConnectionAnswer = deviceId => {
if (!anwsered.includes(deviceId)) {
setAnswered(prev => [...prev, deviceId]);
}
};
}
you're doing it right or you can simply do it like
if (!anwsered.includes(deviceId)) {
setAnswered([...answered, deviceId]);
}

Different values of state in different places

I'm currently learning react and came to the following problem.
When I start dragging div I update state writing div's id in it.
useEffect - writes that it's updated.
console.log() before return does the same.
So if I'm not mistaken, it comfirms that state updated. (I used it to debug and to see if state even updates)
But when dropHandler runs, it says that startBlock is ''. So it doesn't contain value.
export function SomePage() {
const [startBlock, setStartBlock] = useState('') # using this state to store id of start div.
useEffect(() => {
console.log("changed to", startBlock)
}, [startBlock])
function dragStartHandler(e) {
setStartBlock(e.currentTarget.parentElement.id);
}
function dropHandler(e) {
e.preventDefault();
console.log('drop', startBlock)
}
console.log(startBlock)
return (
<div draggable dragStartHandler={dragStartHandler} dropHandler={dropHandler}> # simplified doesn't really matter
)
}
I know that useState is async. But as I already said, useEffect printed that value was updated. So I'm quite confused.
The questions are:
Why startBlock in dropHandler doesn't have value?
How can I fix it?
The attributes you're looking for are called onDragStart and onDragEnd. Correct the names and it works properly.
export function SomePage() {
const [startBlock, setStartBlock] = useState('') # using this state to store id of start div.
useEffect(() => {
console.log("changed to", startBlock)
}, [startBlock])
function dragStartHandler(e) {
setStartBlock(e.currentTarget.parentElement.id);
}
function dropHandler(e) {
e.preventDefault();
console.log('drop', startBlock)
}
console.log(startBlock)
return (
<div draggable onDragStart={dragStartHandler} onDragEnd={dropHandler}> # simplified doesn't really matter
)
}
https://codesandbox.io/s/react-playground-forked-od6bcr?file=/index.js

React state is not updating immediately after setState is being called

I am building the frontend of a web based software and I want to add new note every time I press add button.
But it's simply not happening. New note is being rendered only when I change the state of another object. Right below I ma attaching the code. Please help, I am stuck here.
const [allnotes, setAllNotes] = useState(notes)
const addNote = () => {
let notesAllTemp = allnotes;
allnotes.forEach((n, index) => {
if((n.id === clickedId)){
notesAllTemp[index].notesDescs.push({id:
notesAllTemp[index].notesDescs.length+1,desc:''})
setAllNotes(notesAllTemp)
}
});
}
If anyone can figure this out, please help.
Please don't make mistake by directly updating the array element by its index you should first copy the array into a new array, otherwise, it will directly update the array which will cause reacjs to not to re-render the component.
Check this out
const [allnotes, setAllNotes] = useState(notes)
const addNote = () => {
let notesAllTemp = [...allnotes]; // !IMPORTANT to copy array
allnotes.forEach((n, index) => {
if((n.id === clickedId)){
notesAllTemp[index].notesDescs.push({id:
notesAllTemp[index].notesDescs.length+1,desc:''})
}
});
setAllNotes(notesAllTemp);
}
Better if you first modify the array then update at once
const [allnotes, setAllNotes] = useState(notes)
const addNote = () => {
let notesAllTemp = allnotes;
allnotes.forEach((n, index) => {
if((n.id === clickedId)){
notesAllTemp[index].notesDescs.push({id:
notesAllTemp[index].notesDescs.length+1,desc:''})
}
});
setAllNotes(notesAllTemp)
}

array of objects always return 0 ,although it has more than one object inside

I'm getting data from react-redux and want to disable the button if the number of array items is ===0. but I always getting the value of 0 from myPetArray.length ,although it has more than one element inside it ,and I'm able to verify that as you see in image below the console show 0 element inside array but redux dev tools show real data (two object inside array)
thank you :)
const dispatch = useDispatch()
//status of the next button
const [nextButton, setNextButton] = useState(false)
//part of state that return myPetArray
const petListByUserId = useSelector((state) => state.petListByUserId)
const { myPetArray, myPetArraySuccess } = petListByUserId
useEffect(() => {
dispatch(getPetListByUserId(userId))
if (myPetArray && myPetArray.length === 0) {
console.log(mypetArray.length)
setNextButton(true)
}
}, [userId,myPetArray ])
<Button disabled={nextButton}>Next Step</Button>
I'm not sure, but it might be worth trying:
console.log(mypetArray[0].length)

.map is not a function (am I really not using an array here?)

I'm trying to learn some react hooks by practice and trying to change the state at the same time.
Here is what my useState hook looks like:
const [names, setNames] = useState([
"James",
"Jessica",
"Roger",
"Alfred"
])
I have used JSX to return the array items from "names" on the page as follows:
{names.map((name)=> {
return <p>{name}</p>
})}
This seems to display everything just fine, suggesting that the map function works correctly on the array called names.
However, when I create a function to update the state using setNames, I get the error "TypeError: names.map is not a function"
Here is what the function looks like:
const addName = () => {
setNames({
names: [...names, "Jessica"]
})
}
I am just running this in an onClick event through a button in the app:
<button onClick={addName}>Add</button>
Sorry in advanced if this is novice but I can't seem to understand why I'm getting this error. I understand that .map can only be used on an array, however that's what I thought names was.. an array. Also it displays names when I use the .map function so I'm just confused by the error itself.
Thanks in advance for any help.
setNames({
names: [...names, "Jessica"]
})
This is changing your state to no longer be an array, but rather to be an object with a .names property on it. Only in class components do you need to pass in an object when setting state.
Instead, you should do the following:
setNames([...names, "Jessica");
One slight improvement you could do is to use the function version of setNames. This will make sure you're always using the most recent version of the state, and thus eliminate the possibility of some bugs when setting state multiple times:
const addName = () => {
setNames(prev => {
return [...prev, "Jessica"];
});
}
You're using the old setState logic.
setNames accepts the new value as first param, not an object, to add a name, change the addName to the following:
const addName = () => {
setNames([...names, "Jessica"])
}
Correct modification of state arrays in React.js
Working example:
const {useState} = React;
const SameSet = () => {
const [names, setNames] = useState([
"James",
"Jessica",
"Roger",
"Alfred"
]);
const addName = () => {
setNames([...names, "Jessica"])
}
return (
<div>
{names.map((name) => <p>{name}</p>)}
<button onClick={addName}>Add</button>
</div>
)
}
ReactDOM.render(<SameSet />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Resources