How to correctly initialize a state array React JS - reactjs

I need to initialize a state array with six elements, points, and then update the proper element in the points array when setVote function is called:
const [selected, setSelected] = useState(0)
const setNextItem = (value) => setSelected(value)
const initialValue = new Array(6).fill(0);
const [points, setPoint] = useState(initialValue)
const setVote = (value) => setPoint(value)
// randomly choose the next item
const setNextitem(Math.floor((Math.random() * 5) + 0))
const setVote => {
const copy = [...points]
copy[selected] += 1
return copy;
}
However, when I view points and copy arrays in the console window, points never gets updated with copy. It stay as Array(6) [ 0, 0, 0, 0, 0, 0 ]. Is it always initializing or is the copy array not retuned. What is the correct way to do this?
Here is my final code:
```
const App = () => {
const [selected, setSelected] = useState(0)
const [points, setPoints] = useState(new Array(6).fill(0))
const setNextItem = (value) => setSelected(value)
const setVoteAt = (value) => setPoints(value)
console.log(selected, points)
const next_button = {
name : 'next item',
onClick: () => setNextItem(Math.floor((Math.random() * 5) + 0))
}
const vote_button = {
name : 'vote',
onClick: () => setVoteAt(UpdatePoints(selected))
}
const UpdatePoints = (index) => {
let copy = [...points]
copy[index]++
return copy
}
```

Too many duplicated function and state
Just a little order the code..
react useState is not rective, then you can do useEffect to console.
And then you will see the update array.
const [points, setPoints] = useState(new Array(6).fill(0));
const UpdatePoints = (selected) => {
let copy = [...points];
copy[selected]++;
setPoints(copy);
}
const random = () => Math.floor((Math.random() * 5) + 0)
useEffect(() => console.log(points))
return (
<div onClick={() => UpdatePoints(random())}> ClickMe </div>
);

It looks like it should work for the most part. I'd say these two functions are conflicting, and causing an issue. Are there any errors returned in the console?
const setVote = (value) => setPoint(value)
const setVote => {
const copy = [...points]
copy[selected] += 1
return copy;
}
This last one you may want to rename. Something like setVoteAt which take an index parameter for which vote to set.
const setVoteAt = (index) => {
const copy = [...points]
copy[index] += 1
return copy;
}
setVoteAt(2) // [0, 0, 1, 0, 0, 0]

How to correctly initialize a state array React JS
Use useEffect to initialize it properly. This is similar to componentDidMount.
const [points, setPoints] = useState([])
useEffect(() =>
{
const initialValue = new Array(6).fill(0);
setPoints(initialValue);
}
, []) // initialize only once (on mount) and not on every render
Is it always initializing or is the copy array not retuned. What is the correct way to do this?
setVote() is not doing things correctly. You can update points every time selected is changed by:
useEffect(() =>
{
setPoints(points => {
points[selected] += 1
return points
})
}
, [selected] // only run this effect every time selected changed
)
setNextItem(2) // this will update selected then run the effect on top
// and also increment points[selected]

Related

background change every second

I need to make background change every second. if i use setinterval. the background changes too fast.
here's my code:
const { url, id, isButtonPrev, isButtonNext } = useOwnSelector(state => state.sliderReducer);
const img = useRef<HTMLImageElement>(null);
const dispatch = useOwnDispatch();
Here's function which chang background
const setBackGround = (index: number | null = null) => {
console.log(index)
if(img.current) {
img.current.src = `${url}${id < 10 ? `0${id}` : `${id}`}.jpg`;
img.current.onload = () => {
document.body.style.backgroundImage = `url(${img.current?.src})`;
if (index) dispatch(setId(index));
dispatch(isButton(''));
}
}
}
then I call this function:
setBackGround();
setInterval(() => {
setBackGround(id + 1);
}, 1000);
but background change very fast
I also tried to use the useEffect hook. But it didn’t help either
useEffect( () => {
const intervalID = setInterval(() => {
setBackGround(id + 1);
}, 1000);
return clearInterval(intervalID);
}, []);
useRef returns an object like {current: "value"}.Therefore, you need to use it as follows.
const imgRef = useRef<HTMLImageElement>(null);
if(imgRef.current){
imgRef.current.src = url;
}

When I try to push an element to a array but it takes only one rest of the elements are got removed automatically. It happen when use useState hook

const [filter, setFilter] = useState([]);
let brandList = [];
const handleCheckBox = (e) => {
const { value, checked } = e.target;
if (checked) {
brandList.push(value);
} else {
let ind = brandList.indexOf(value);
brandList.splice(ind, 1);
}
console.log(brandList);
setFilter([...brandList]);
};
When I try to push an element to an array but it takes only one rest of the elements are got removed automatically. It happens when I using the useState hook.
Please checkout the image below:
brandList is redeclared an empty array each render cycle. This is why you only ever see that last filter item value added.
Use the filter state directly.
Example:
const [filter, setFilter] = useState([]);
const handleCheckBox = (e) => {
const { value, checked } = e.target;
if (checked) {
setFilter(filter => [...filter, value]);
} else {
setFilter(filter => filter.filter(el => el !== value));
}
};

How can I use useMemo dependent on the webapi

I have a webapi invoked that is working properly:
const [pItem, setPItem] = useState([]);
const [weight, setWeight] = useReducer(weightHandler, 0.0);
useEffect(() => {
setLoading(true);
let mounted = true;
(async function () {
await getPlantInfoById(itemId)
.then(item => {
if (mounted) {
setPItem(item)
setLoading(false);
}
})
})();
return () => { mounted = false; }
}, [itemId])
Here pItem contains data now I have another filled called weight(which can be changed by a user) .
So I need some calculations according to the weight changes:
const PaymentCalculator = function () {
const [item] = [...pItem];
const priceWithDiscount = DiscountCalc(item.price, item.discount);
const divideWeight = weight / item.weight;
const result = (divideWeight * priceWithDiscount) * 1000;
return result;
}
const use = useMemo(() => PaymentCalculator(), [weight])
But it seems PaymentCalculator invoked before useEffect !!
How can I fix this?
If you examine the contents of paymentCalculator you'll see you've more than just weight as a dependency.
const PaymentCalculator = function () {
const [item] = [...pItem];
const priceWithDiscount = DiscountCalc(item.price, item.discount);
const divideWeight = weight / item.weight;
const result = (divideWeight * priceWithDiscount) * 1000;
return result;
}
pItem is also a dependency!
Initially pItem is an empty array, and since all hooks are called on each render cycle, this would mean that item is undefined on the initial render and accessing item.price and item.discount will throw an error for attempting to "access X of undefined".
Add pItem to the dependency array and provide a fallback value.
const paymentCalculator = function() {
const [item = {}] = [...pItem];
const priceWithDiscount = discountCalc(item.price, item.discount);
const divideWeight = weight / item.weight;
const result = (divideWeight * priceWithDiscount) * 1000;
return result;
}
...
const use = useMemo(() => PaymentCalculator(), [pItem, weight]);

useState array destructuring react

I always see this type of code:
const [value, setValue] = useState(null);
since value can be changed using setValue, why are we using const for value.
What const means is that the value for that identifier in that scope cannot be reassigned. You can't do
const x = 5;
x = 6;
or
function foo(arg) {
const theArg = arg;
theArg = 5;
}
But there's nothing stopping you from running the function again, resulting in a new binding for that variable:
function foo(arg) {
const theArg = arg;
}
foo(5);
foo(6);
The above is what React is doing - it runs the whole function component again, which results in useState returning the updated state. No const identifier ever gets reassigned.
Another example:
let i = 0;
const useState = () => [i, newI => { i = newI; TheComponent(); }];
const TheComponent = () => {
const [i, setI] = useState();
console.log('component running with i of', i);
setTimeout(() => {
setI(i + 1);
}, 1000);
};
TheComponent();

React useEffect: Why is my value undefined initially?

I'm trying to setup an onKeyPress event listener and I'm confused as to why the initial value is undefined and then the value I want. The data is added on mount (see x in console). Why am I unable to immediately capture it and instead get an initial undefined, especially since it clearly already exists in state?
useEffect(() => {
console.log('x', multipleChoice); <-- logs the array of objects
const handleKeyPress = ({ key }) => {
const index = Number(key) - 1;
if (key === '1') {
console.log(multipleChoice[index]); <-- logs undefined, then logs object
}
};
window.addEventListener('keydown', (e) => handleKeyPress(e));
return () => {
window.removeEventListener('keydown', (e) => handleKeyPress(e));
};
}, [allCards, currentCard, multipleChoice]);
LocalState
const [currentCard, setCard] = useState(0);
const [multipleChoice, setMultipleChoice] = useState([]);
// allCards is passed as a prop on page load from the parent
When the user guesses an answer correctly the currentCard is incremented by 1
UseEffect that sets multipleChoice
useEffect(() => {
const generateMultipleChoice = (words: Word[]) => {
const possibleAnswers = words.reduce(
(accum: Word[]) => {
while (accum.length < 4) {
// randomly select words from pool
const index = getRandomInt(0, allCards.length - 1);
const randomWord = allCards[index];
// verify current hand doesn't already have that word
if (!accum.includes(randomWord)) {
accum.push(randomWord);
}
}
return accum;
},
// default with the current card already in the hand
[allCards[currentCard]]
);
// return the hand with the matching card and (3) other cards from pool
return possibleAnswers;
};
const shuffledCards = shuffle(generateMultipleChoice(allCards));
setMultipleChoice(shuffledCards);
}, [allCards, currentCard]);
screenshot of console
This is it:
// initial state
const [multipleChoice, setMultipleChoice] = useState([]);
// therefore, initially, if index is any Number
console.log(multipleChoice[index]) // undefined
The object is returned, only until the calculation is finished...
useEffect(() => {
// ...
// this has to run before `multipleChoice` is updated to return that object
const shuffledCards = shuffle(generateMultipleChoice(allCards));
setMultipleChoice(shuffledCards);
}, [allCards, currentCard]);

Resources