Global variables in React Native - javascript

let check1 = 0;
const App: () => React$Node = () => {
const video = useRef();
const [check2, setCheck2] = useState(0);
let check3 = 0;
useEffect(
() => {
askPermission().then((record) => {
if (record) {
RNSoundLevel.start();
RNSoundLevel.onNewFrame = (data) => {
if(check1 < 10) check1++;
if(check2 < 10) setCheck(check2++);
if(check3 < 10) check3++;
}
}
});
If check1, the value can be read and written normally.
check2 and check3 give the value (0) at the time of the first render.
It seems that it can be solved by using check1, but the code does not seem to be clean.
I want to use check2, is there a way to read it?

Related

Use state in React causing value of const to break

I'm trying to make an app where the user can cycle through a pack of cards. I'm trying to make it so each card is unique so that a user cannot pick two of the same card consecutively. Therefore the way I thought of doing this was by adding all the cards to an array and then shuffling that array.
import * as React from "react";
import { View, Text, Button } from "react-native";
import homeStyles from "../styles/homeStyles";
import { cardsList } from "../assets/cardsList";
import { useEffect, useState } from "react";
export default function Home() {
const [CurrentQuestion, setCurrentQuestion] = useState(1);
const [usedQuestions, setUsedQuestions] = useState([]);
const test = [];
const length = cardsList.length;
const shuffle = () => {
let i,
x = 0,
y = 0,
temp0 = 0;
for (i = 0; i < usedQuestions.length; i++) {
x = Math.floor(Math.random() * usedQuestions.length);
y = Math.floor(Math.random() * usedQuestions.length);
if (x === y) {
//for dont change arr[index] with self !!!
continue;
}
temp0 = usedQuestions[x];
usedQuestions[x] = usedQuestions[y];
usedQuestions[y] = temp0;
}
console.log("Shuffled : " + usedQuestions);
};
let i = 0;
const nextQuestion = () => {
let plz = null;
if (i <= usedQuestions.length) {
// plz = usedQuestions[i]
setCurrentQuestion(usedQuestions[i]);
i = i + 1;
} else {
i = 0;
// shuffle()
// nextQuestion()
}
// console.log(plz)
console.log(CurrentQuestion);
};
const start = () => {
let i = 1;
while (i <= length) {
test.push(i);
i++;
}
console.log("initial : " + test);
setUsedQuestions([...usedQuestions, ...test]);
};
return (
<View style={homeStyles.container}>
<View style={homeStyles.card}>
{cardsList
.filter(function (item) {
return item.id === CurrentQuestion;
})
.map((cardsList) => {
return (
<View key={cardsList.id}>
<View style={homeStyles.line}>
<Text style={homeStyles.cardNumber}>
{cardsList.id}) {cardsList.title}
</Text>
</View>
<Text style={homeStyles.cardText}>{cardsList.cardText}</Text>
</View>
);
})}
<Button
style={homeStyles.button}
title="Shuffle"
onPress={() => shuffle()}
/>
<Button
style={homeStyles.button}
title="Next Question"
onPress={() => nextQuestion()}
/>
<Button
id="test"
style={homeStyles.button}
title="Start"
onPress={() => start()}
/>
</View>
</View>
);
}
The section below is the section causing me issues
let i = 0;
const nextQuestion = () => {
let plz = null;
if (i <= usedQuestions.length) {
// plz = usedQuestions[i]
setCurrentQuestion(usedQuestions[i]);
i = i + 1;
} else {
i = 0;
// shuffle()
// nextQuestion()
}
// console.log(plz)
console.log(CurrentQuestion);
};
The const plz works perfectly returning the value of the cards one by one from the shuffled array. See Image
However when I try and use the UseState feature from react to set this value so that I can use it to display the correct part in the app section it breaks.
Any idea why this happens and how I can fix it? I'm fairly new to coding so any tips on how I could better it would be appreactiated.
You cannot modify a state directly
You can create a copy, shuffle it and reassign the state in this way
const shuffle = () => {
setUsedQuestion(u => {
const data = [...u]
data.sort(() => Math.random() - 0.5))
console.log("Shuffled : " + data);
return data;
}
)
}
Everytime you update a react state (eg. by calling setCurrentQuestion) your component will rerender.
Here, rerendering means it will execute the code of your function component again (function Home()).
In the body of function Home() you have this: let i = 0; so i will reset everytime you change a local state.
Now what you probably want is to persist the current question index across multiple rerenders.
you could do nextQuestion like this:
// remove: const [CurrentQuestion, setCurrentQuestion] = useState(1);
const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
const currentQuestion = usedQuestions[currentQuestionIndex];
const nextQuestion = () => {
if (currentQuestionIndex < usedQuestions.length) {
setCurrentQuestionIndex(currentQuestionIndex + 1);
} else {
setCurrentQuestionIndex(0);
}
};
You might have more tweaking to do but that should get you started

When a key is pressed, the event occurs twice

When I press a key using keyEvent, then I call the function, it is below.
const GeneratedKey: FC<IGenerated> = (props) => {
const [keyBoard, setKeyBoard] = useState("")
const [arrayMovie, setArrayMovie] = useState<string[]>([])
const idPage = props.idpage
const nameMovie = data.results[idPage].title
const [idLetter, setIdLetter] = useState<number>(0)
const [indexArray, setIndexArray] = useState<number[]>([])
const arrayNameMovie = nameMovie.split(" ").join("").split("");
const getKey = (e: any) => {
console.log("test")
const key = e.key
let count = 0
for (let i = 65; i <= 90; i++) {
if (key.toUpperCase() == String.fromCharCode(i)) {
count = 1
} else if (key.toLowerCase() == "backspace") {
count = 10
}
}
if (count == 1) {
indexArray.sort(function (a: any, b: any) {
return a - b;
})
arrayMovie.splice(indexArray[idLetter], 1, key)
setIdLetter(idLetter + 1)
} else if (count == 10) {
if (idLetter >= 1) {
setIdLetter(idLetter - 1)
arrayMovie.splice(indexArray[idLetter], 1, "")
}
}
setKeyBoard(key)
document.removeEventListener("keydown", getKey);
}
useEffect(() => {
for (let i = 3; i >= 0; i--) {
const randomIndex = Math.floor(Math.random() * arrayNameMovie.length)
arrayNameMovie.splice(randomIndex, 1, " ")
indexArray.push(randomIndex)
}
setIdLetter(indexArray[0])
setArrayMovie(arrayNameMovie)
}, [])
document.addEventListener("keydown", getKey)
return (
<div className="down__word">
{arrayMovie.map((letter: any) =>
<LettersView letters={letter} props={undefined} />
)}
</div>
)
}
In fact, it should be called once, but it fires twice, as you can see from console.log();
How can I fix this, I can also show other files with code, but this is unlikely to help
This is due to your component may get rendered twice (due to change of props or any external reason). Moreover I think this is not the correct way to handle the event listener in FC. You should consider the useEffect for registration / un-registration of event listener.
useEffect(() => {
const handler = () => {};
document.addEventListener('keydown', handler);
return () => {
document.removeEventListener('keydown', handler);
}
}, [deps]); // if you have any changing dependency else just remove the array to execute the UseEffect everytime.
This will ensure that you have registered the event only once in your code.
Refer https://reactjs.org/docs/hooks-effect.html

Use a prop function inside useEffect return: prop.function is not a function

I am currently trying to build an next.js app.
So what I want to do is passing a function to a component and call it with useEffect
I have the following component in order to change the props of the parents element. Therefore I pass the function from the parent like this:
<NumberInput name="height" update={manuelUpdate}></NumberInput>
The manuelUpdate function is a another props function from the actual parent:
const manuelUpdate = (name, value) => {
props.update(name, value);
};
It works fine if I run the props.function with the onclick functions. However as soon as I try to use it in useEffect, it returns that the function is not a function.
Maybe I am just thinking to complicated..
this is the component;
const NumberInput = ({ name, min = undefined, max = undefined, ...props }) => {
const minInput = min !== undefined
? min
: null;
const maxInput = max !== undefined
? max
: null;
const [numb, setNumb] = useState(0);
useEffect(() => {
console.log(props.update)
}, [numb]);
const increaseNumb = () => {
if (numb < maxInput || maxInput == null) {
setNumb(numb + 1)
}
props.update(name, numb)
};
const decreaseNumb = () => {
if (numb < minInput || minInput == null) {
setNumb(numb - 1)
}
};
const changeHandler = ({ e }) => {
let n = parseInt(e.target.value)
if (Number.isNaN(n)) {
setNumb(numb)
} else {
setNumb(n)
}
}
return (
<div className={styles.def_number_input, styles.number_input}>
<button onClick={decreaseNumb} className={styles.minus}></button>
<input className={styles.quantity} name="quantity" value={numb} onChange={(e) => changeHandler({ e })}
type="number" />
<button onClick={increaseNumb} className={styles.plus}></button>
</div>
);
};
sorry in advance if my question is stupid or my code messy, I am still in the process of learning :D
Issue was related to another problem. I was accidentally calling the component 2 times and forgot to adjust the parameters. CASE CLOSED

'This' undefined in parsing the xml API using react

I have been trying to make a data from XML clickable in react. This is working in one of the function but gives an error when it is called in an another function.
Shows = Unhandled Rejection (TypeError): Cannot read property 'getAuthArticles' of undefined
I have tried using bind(this). I am already using the arrow functions
getData() {
fetch(`http://export.arxiv.org/api/query?search_query=ti:${'therapy'}&sortBy=lastUpdatedDate&sortOrder=ascending`).then(data=>data.text()).then(str => (new window.DOMParser()).parseFromString(str, "text/xml")).then(data => {
var entry = data.getElementsByTagName("entry");
let elems = []
for(let i=0;i<entry.length;i++){
console.log(entry);
let elem = <div key={i} id={entry[i].getElementsByTagName("id")[0].textContent} onClick={this.handleChange}>{entry[i].getElementsByTagName("title")[0].textContent}</div>;
elems.push(elem);
}
console.log(elems)
this.setState({data: elems});
})
}
/* */
handleChange(evt) {
console.log(evt.target.id)
var res = evt.target.id.split("/");
var id = res[5]
fetch(`http://export.arxiv.org/api/query?id_list=${res[4]}/${id}`)
.then(data=>data.text()).then(str => (new window.DOMParser()).parseFromString(str, "text/xml"))
.then(data => {
var summ = data.getElementsByTagName("summary");
let auth = data.getElementsByTagName("author");
let elems1 = [];
let name = [];
console.log(auth)
for (let i = 0; i < auth.length; i++ ){
console.log(auth[i].textContent);
console.log(auth[i].getElementsByTagName("id"));
let elem1 = <div key={i} id={auth[i].textContent} onClick={this.getAuthArticles.bind(this)}>{auth[i].textContent}</div>;
name += auth[i].textContent;
// elems1.push(elem1);
// console.log(elem1)
}
document.getElementById("demo").innerHTML = summ[0].textContent + name;
// window.history.pushState({}, "page 2", "bar.html");
// this.setState({data: elems1});
})
}
getAuthArticles(evt) {
console.log(evt.target.id)
let auth_name = evt;
fetch(`http://export.arxiv.org/api/query?search_query=${auth_name}`)
.then(data=> data.text()).then(str => (new window.DOMParser()).parseFromString(str, "text/xml"))
.then(data => {
var arti = data.getElementsByTagName("title");
let titles = []
for(let i=0;i<arti.length;i++){
let elem = <div key={i} id={arti[i].getElementsByTagName("id")[0].textContent}>{arti[i].getElementsByTagName("title")[0].textContent}</div>;
titles.push(elem);
}
console.log(titles)
})
}
I see you're using normal function and you missing bind(this) in getData()
onClick={this.handleChange}
// should change to
onClick={this.handleChange.bind(this)}
And make sure you bind(this) for getData()
It will easier with arrow function like
handleChange = (evt) => {}
you don't need to bind(this) for arrow function

Display backend data in reactJS

i am trying to display backend data in the front with react, i did recieve the data because when i inspect the response in the Network tab in the console i found them,
now to display this data on the interface i am calling the loadData() function in componentDidMount :
componentDidMount() {
this.loadTime();
this.loadOtherData();
}
but in these two function i am using a setTimeOut() so i can display if i don't do a setTimeOut i'm getting null on the render
loadTime() {
const dateList = [];
$('.day').each((index, d) => {
dateList.push(new Date(d.innerText));
});
const displayImputation = {
idMantis: $('#mantis').html(),
dateList: dateList,
userId: 1
};
this.props.store.loadImputation(displayImputation);
setTimeout(() => {
const response = this.props.store.privateImputationData;
for (let i = 0; i < response.length; i += 1) {
const stampToDate = response[i].cra.date;
const o = moment(stampToDate).day();
for (let x = 0; x < $('.App input').length; x += 1) {
if (x === o) {
const input = $('.App input')[x - 1];
input.value = response[i].temps;
}
}
}
}, 500); }
is it a good practice or is there another solution ?

Categories

Resources