I'm pretty new to this and can't really figure out how the render works - stuck with UseState for now :) -. Since I see a lot of people using it I wanted to ask for advice on what I'm doing wrong. Here are 2 examples one with UseState that works great and other with render that does nothing, I added some style so it looks kind of acceptable for anyone trying it out.
Any help appreciated, thank you
// USESTATE
const [newColor, setNewColor] = useState('green');
useEffect(() => {
setBorder()
}, [newColor])
function setBorder() {
if (newColor === 'green') {
document.getElementById('green').style.borderColor = "orange";
document.getElementById('yellow').style.borderColor = "black";
document.getElementById('red').style.borderColor = "black";
}
if (newColor === 'yellow') {
document.getElementById('yellow').style.borderColor = "orange";
document.getElementById('green').style.borderColor = "black";
document.getElementById('red').style.borderColor = "black";
}
if (newColor === 'red') {
document.getElementById('red').style.borderColor = "orange";
document.getElementById('green').style.borderColor = "black";
document.getElementById('yellow').style.borderColor = "black";
}
}
const changeBg = () => {
document.body.style.backgroundColor = newColor;
}
return (
<div>
<div style={{width: '240px', height: '88px', border: '3px solid black', 'borderRadius': '10px'}}>
<div id="green" onClick={(e) => setNewColor(e.target.id)} style={{width: '40px', height: '40px', background: 'green', border: '3px solid black', float: 'left', margin: '20px 0 0 30px', 'borderRadius': '10px', cursor: 'pointer'}}></div>
<div id="yellow" onClick={(e) => setNewColor(e.target.id)} style={{width: '40px', height: '40px', background: 'yellow', border: '3px solid black', float: 'left', margin: '20px 0 0 20px', 'borderRadius': '10px', cursor: 'pointer'}}></div>
<div id="red" onClick={(e) => setNewColor(e.target.id)} style={{width: '40px', height: '40px', background: 'red', border: '3px solid black', float: 'left', margin: '20px 0 0 20px', 'borderRadius': '10px', cursor: 'pointer'}}></div>
</div>
<button onClick={changeBg}>SAVE</button>
</div>
);
// RENDER
class Test1 extends Component {
constructor(props) {
super(props);
this.state = {
newColor: 'green'
}
}
componentDidUpdate() {
if (this.newColor === 'green') {
document.getElementById('green').style.borderColor = "orange";
document.getElementById('yellow').style.borderColor = "black";
document.getElementById('red').style.borderColor = "black";
}
if (this.newColor === 'yellow') {
document.getElementById('yellow').style.borderColor = "orange";
document.getElementById('green').style.borderColor = "black";
document.getElementById('red').style.borderColor = "black";
}
if (this.newColor === 'red') {
document.getElementById('red').style.borderColor = "orange";
document.getElementById('green').style.borderColor = "black";
document.getElementById('yellow').style.borderColor = "black";
}
}
render() {
const changeBg = () => {
document.body.style.backgroundColor = this.newColor;
}
return (
<div>
<div style={{width: '240px', height: '88px', border: '3px solid black', 'borderRadius': '10px'}}>
<div id="green" onClick={(e) => this.state={newColor: e.target.id}} style={{width: '40px', height: '40px', background: 'green', border: '3px solid black', float: 'left', margin: '20px 0 0 30px', 'borderRadius': '10px', cursor: 'pointer'}}></div>
<div id="yellow" onClick={(e) => this.state={newColor: e.target.id}} style={{width: '40px', height: '40px', background: 'yellow', border: '3px solid black', float: 'left', margin: '20px 0 0 20px', 'borderRadius': '10px', cursor: 'pointer'}}></div>
<div id="red" onClick={(e) => this.state={newColor: e.target.id}} style={{width: '40px', height: '40px', background: 'red', border: '3px solid black', float: 'left', margin: '20px 0 0 20px', 'borderRadius': '10px', cursor: 'pointer'}}></div>
</div>
<button onClick={changeBg}>SAVE</button>
</div>
);
}
}
CodePudding user response:
First of all, you should never* update DOM directly in react as you do.
In both of the examples you are doing that.
The reason why second example doesn't work, componentDidUpdate
is called when update happens (e.g. state change or props change), that doesn't happen because you aren't calling setState
in second example; rather directly assigning to this.state
. Also it should be this.state.newColor
as noted in comments.
Idiomatic way to solve this in react is this:
export default function App() {
const [newColor, setNewColor] = React.useState('green');
const changeBg = () => {
document.body.style.backgroundColor = newColor;
};
return (
<div>
<div
style={{
width: '240px',
height: '88px',
border: '3px solid black',
borderRadius: '10px',
}}
>
{['green', 'yellow', 'red'].map((x) => (
<div
onClick={(e) => setNewColor(x)}
style={{
width: '40px',
height: '40px',
background: x,
border: '3px solid black',
borderColor: newColor === x ? 'orange' : 'black',
float: 'left',
margin: '20px 0 0 30px',
borderRadius: '10px',
cursor: 'pointer',
}}
></div>
))}
</div>
<button onClick={changeBg}>SAVE</button>
</div>
);
}
Although the boxes aren't well centered now, because you had different margin for first element, when all div
s were written out by hand. But now I have same margin for all of them because I used a loop. I will leave it up to you to adjust it.
* Well in rare cases you can, when say integrating with 3rd party libraries, but in that case you should make sure react doesn't touch that part of the DOM.