There is soemthing weird happening with me in react
for some reason changing the background image of a div like that works:
document.getElementById("player1-card1").style.backgroundImage =
`url(${require(../images/3.png)})`
But like that wont work
const y = 3
const x = `../images/${y}.png`
document.getElementById("player1-card1").style.backgroundImage =
`url(${require(x)})`
x is the same value as ../images/3.png so why it is not working I am confused
You shouldn't be using document.getElementById in React. If you want to set the style in react, import the image and then just pass it into the style prop.
import img from "../images/3.png"
<div style={{backgroundImage: img}}
I don't remember how websockets api looks like, but your code should utilize state like that:
const Component = () => {
const [image, setImage] = useState();
useEffect(() => {
socket.onMessage = (data) => {
setImage(data)
}
})
return <div style={{ backgroundImage: image }} />
}
Related
Update: Problem found - the onChange event is fired on component render, this overwrites what happens in the useEffect... not sure how to address this conflict, might have to dig into the installed component.
Update 2: "Solution" was to put a setTimeout in the onChange event for the slider, and a slightly longer setTimeout on the useEffect so that they resolved in the correct order.
I'm using a slider component in react from here - it is working properly.
I am trying to update the minimum and maximum slider values + the actual value of the sliders whenever a chartData set is updated using useEffect();
Despite setting some states within useEffect, these states aren't being rendered by the component.
The chartData is being retrieved asynchronously from the backend, which may contribute to this problem.
Here is my code:
//Histogram block size
const blockSize = 5000;
//Initial boundaries for histogram slider
const initialMin = 15000;
const initialMax = (labels.length-1)*blockSize;
const [max, setMax] = useState(initialMax);
//States for histogram slider
const [minValue, setMinValue] = useState(initialMin);
const [maxValue, setMaxValue] = useState(initialMax);
//Update histogram sliders when new data is input
useEffect(()=>{
setMax(initialMax)
setMinValue(initialMin)
setMaxValue(initialMax)
}, [chartData])
//Handle histogram sliding
const handleInput = (e) => {
setMinValue(e.minValue);
setMaxValue(e.maxValue);
};
return (<div className = 'Chart' style={{position: 'relative', width: "62vh"}}>
<Bar options={options} data={data}/>
<MultiRangeSlider
min={0}
max={max}
step={blockSize}
minValue={minValue}
maxValue={maxValue}
onChange={(e) => {
handleInput(e);
}}
/>
Chart data is coming from:
//chartData state passed to Chart component
const [chartData, setChartData] = useState(initialChartData);
const buttonClickFunction = ()=>axios.get('/api/v1/data', {'params': ['python', 'javascript' , 'c++']})
.then((res)=>{
setChartData(res.data);
});
As part of the rendered component:
...
<Chart chartData={chartData}></Chart>
...
I'm just playing around with the reactjs useTransition hook and trying to understand how to use it. I've gone through almost everything on the doc. The example given there is working as expected.
I'm trying to use this hook in a different context, but this time it doesn't seem to be working. Here's my code below:
import { useState, useTransition } from "react";
function Component() {
const [slow, setSlow] = useState(0);
const [fast, setFast] = useState(0);
const [isPending, startTransition] = useTransition();
const handleSlowClick = () => {
startTransition(() => {
let starting = performance.now();
while (performance.now() - starting < 5000) {
// do nothing for 5sec
}
setSlow((prev) => prev + 1);
});
};
const handleFastClick = () => {
setFast((prev) => prev + 1);
};
return (
<>
<button onClick={handleSlowClick}>slow - {slow}</button>
<button onClick={handleFastClick}>fast - {fast}</button>
</>
);
}
export default Component;
react is supposed to give everything inside the startTransition function less priority when updating states. But this isn't the case in the browser. When I click the slow button, it makes the whole web page unresponsive for 5 sec
I wonder what's happening under the hood?
[NOTE: I'm trying it inside my current NextJS project, in case it matters]
I have an application in react native where i'm developing a search feature like Instagram.
It is like if user stop typing show him his query result.
my current approach is messing up redux. And sometimes it returns same element multiple times or sometime random elements which are irrelevant of that query.
right now. I'm calling search api immediately as use start typing in searchbar.
here is code below of my component.
import { getSearchDataApi } from "../../api/search/search";
import { clearSearchData, setSearchData } from "../../redux/action/search";
const SearchScreen =(props)=>{
const [autoFocus,setAutoFocus] = useState(true)
const [keyWord,setKeyWord] = useState(null)
const [isLoading,setIsLoading] = useState(false)
const [isError,setIsError] = useState(false)
const [pageNumber,setPageNumber] = useState(1)
const [loadMore,setLoadMore] = useState(true)
const loadMoreDataFunc =()=>{
if (pageNumber <= props.totalSearchPage) {
setPageNumber(pageNumber+1)
}
else {
setLoadMore(false)
}
}
const searchData = async(keyWord)=>{
console.log(keyWord,pageNumber)
try {
setIsLoading(true)
var searchResponse = await getSearchDataApi(keyWord,pageNumber)
props.setSearchData(searchResponse.data)
setIsLoading(false)
}
catch (e) {
setIsError(true)
console.log("Error --- ", e.response.data.message)
showMessage({
message: e.response.data.message,
type: "danger",
});
}
}
return (
<View>
....
</View>
)
}
const mapStateToProps = (state)=>({
searchData: state.searchReducer.searchData,
totalSearchPage: state.searchReducer.totalSearchPage,
})
export default connect(mapStateToProps,{setSearchData,clearSearchData})(SearchScreen);
I will really every thankful to someone how can help me in fixing. Appreciation in advance!
GOAL :
The goal that i want to achieve is when user stop typing then i call searchAPI with the keyword he/she entered in searchBar that's all.
I have also tried setTimeOut but that made things more worse.
The best solution to your problem is to debounce the state variable that is responsible for the user input. This way, you can use the effect hook to watch for changes on the debounced variable, and call the search API if/when conditions for the search API variables are met.
Well, I have put some effort to solve it with setTimeout once again and i have done it by following code of snippet.
useEffect(()=>{
setPageNumber(1)
props.clearSearchData()
const delayDebounceFn = setTimeout(() => {
console.log(keyWord)
if (keyWord) {
searchData(keyWord)
}
}, 500)
return () => clearTimeout(delayDebounceFn)
},[keyWord])
You can use a setInterval to create a countDown starting from 2 to 0, or 3 to 0, put it a state.
whenever user types, onChange is called, the from the callback you reset the countDown.
using useEffect with the countDown as dependency, you can open the search result whenever the countdown reaches 0. (which means the user hasn't typed anything since 2s ago)
this might help for creating the countdown https://blog.greenroots.info/how-to-create-a-countdown-timer-using-react-hooks
I'm building a web app and it contains a dropdown list with various scores. Each score looks like this:
<NavDropdown.Item
key = {i}
id = {score["scoreId"]}
onClick = {(e) => {
setScore(score)
window.location.href = '/home/score'
// do something to go to the score page
}}
>
{score["scoreName"]}
</NavDropdown.Item>
When clicking on a score, I first use setScore() to set the score state to the currently selected score, then redirect to /home/score
<Routes>
<Route path="/score" element={<ScoreHome score={score}/>} />
</Routes>
Problem:
I need to pass the newly set score prop to the <ScoreHome /> component, but useState() is asynchronous so props.score would be undefined on the new page.
useState doesn't have callback functions and I tried to use useEffect for something like this:
useEffect(() => {
window.location.href = '/home/score'
},[score])
But this creates an infinite loop for me (the browser keeps jumping to or refreshing /home/score)
What's the best way to handle this? Thanks!
With React-Router, you can pass a state with your navigation call, like so:
...
const navigate = useNavigate();
...
<NavDropdown.Item
key = {i}
id = {score["scoreId"]}
onClick = {(e) => {
navigate('/home/score', { state: {score} });
}}
>
{score["scoreName"]}
</NavDropdown.Item>
Then in ScoreHome.js
const {state} = useLocation();
// state.score <= your selected score
See docs for more
With the help from #Moath, I was able to navigate to ScoreHome.js with the updated score in useEffect() without causing infinite loops. Here's what I did:
const navigate = useNavigate();
useEffect(() => {
if (score["scoreId"] !== undefined) {
navigate('/home/score',{state:{score, 'overview': false}})
}
},[score])
And in ScoreHome.js:
const location = useLocation()
// got score here
var score = location.state.score
const searchQuery=document.querySelector('#searchQ').value
const p=document.querySelector('p')
const log= (e)=>{
e.preventDefault()
console.log(searchQuery)
p.innerHTML=`${searchQuery}`
fetchData()
}
This is the part of my code in the React app that gives me the error, in particular the first line. the #searchQ is a normal HTTML input field that should start a get request, and fetchData() is a normal fetch API function and it's working properly. that way it gives me this error:
TypeError: document.querySelector(...) is null
App
src/App.js:5
5 | let searchQuery=document.querySelector('#searchQ').value
when I remove the .value it runs normally but of course, it won't fetch the user's input. I tried let instead of const. Also I took the code in a vanilla js, HTML page and it logged successfully, but the same method doesn't work in react.
Any help?
It is considered as a top rated bad practice to use querySelector() or getElementById() except for some specific cases, however in this case you can get to work with useEffect as you need to wait for the component to mount.
useEffect(() => {
const searchQuery = document.querySelector("#searchQ").value;
console.log(searchQuery);
}, []);
A Better version would be
const [value, setValue] = useState("");
const pRef = useRef();
const handleSubmit = (e) => {
e.preventDefault();
pRef.current.innerHTML = value;
console.log(value);
};
const handleChange = (e) => {
setValue(e.target.value);
};
return (
<>
<form onSubmit={handleSubmit}>
<input type="text" value={value} id="searchQ" onChange={handleChange} />
</form>
<p ref={pRef}></p>
</>
);
In react u don't directly load the components just as normal HTML. It uses the render() method and there querySelector method doesn't work.
Either use state to directly control/retrieve the value or use ref as #boxdob said.