Hello I'm creating a progerss bar using ReactJS but I have a problem
My progress bar is going to be a React component and I will pass the progress value in the props
For some reason it seems like document.getElementById() does not find anything
import './MyProgressBar.css'
const MyProgressBar = (props) => {
const value = props.value
const progressbar = document.getElementById("hello");
progressbar.style.width = value + "%"
return (
<div class="progress">
<div id="hello" class="color"></div>
</div>
)
}
export default MyProgressBar
It throws an error that says "Cannot read property 'style' of null at MyProgressBar (MyProgressBar.js:9)....."
The reason for the error is that the element doesn't exist yet as of when you go looking for it. You could "fix" that with a useEffect or useLayoutEffect callback, but that wouldn't be the React approach. Your component will be called to re-render when the props change, so handle rendering in the new state directly:
const MyProgressBar = ({value}) => {
return (
<div class="progress">
<div class="color" style={{width: value + "%"}}></div>
</div>
);
};
This also has the advantage that you can have multiple MyProgressBar instances in the page at the same time.
Live Example:
const {useState, useEffect} = React;
const MyProgressBar = ({value}) => {
return (
<div className="progress">
<div className="color" style={{width: value + "%"}}></div>
</div>
);
};
const App = () => {
const [bar1, setBar1] = useState(0);
const [bar2, setBar2] = useState(0);
useEffect(() => {
const t1 = setInterval(() => {
setBar1(b1 => {
if (b1 < 100) {
++b1;
return b1;
}
clearInterval(t1);
return b1;
});
}, 200);
const t2 = setInterval(() => {
setBar2(b2 => {
if (b2 < 100) {
++b2;
return b2;
}
clearInterval(t2);
return b2;
});
}, 400);
}, []);
return <div>
<div>
Every 200ms:
<MyProgressBar value={bar1} />
</div>
<div>
Every 400ms:
<MyProgressBar value={bar2} />
</div>
</div>;
};
ReactDOM.render(<App/>, document.getElementById("root"));
.color {
background-color: blue;
height: 100%;
}
.progress {
height: 1em;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
This code is running before there is anything on the DOM.
You can use it inside a useEffect, running after the render.
useEffect(() => {
const value = props.value
const progressbar = document.getElementById("hello");
progressbar.style.width = value + "%";
}, [props.value]);
You can also use useRef
You document.getElementById is run before actual rendering, so it could not find any element with that Id
It's not reccomend to use document.getElementById in your Reactjs code, use useRef instead:
function App() {
const divRef = React.useRef();
React.useEffect(() => {
console.log(divRef.current);
}, []);
return (
<div class="progress">
<div ref={divRef} id="hello" class="color"></div>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root"></div>