I am learning React, in my test app, I make 2 identical sets of random colored array that will shuffle and change color every time I click on 'change color' button. however I can not seem to make the Dom updates my array colors even the values of colors change correctly.
import React from 'react';
class Card extends React.Component{
constructor(props){
super(props);
const {r,g,b}=this.props.card
this.state={
style:{
width:'100px',
height:'100px',
display:'inline-block',
backgroundColor:`rgb(${r},${g},${b})`
}
}
}
onClick=()=>{
const {r,g,b}=this.props.card
console.log('color values of the card with index',this.props.id ,' is: ', r,g,b)
}
render(){
const {style}=this.state
return (
<div style={style}>
<button onClick={this.onClick}>card test</button>
</div>
)
}
}
export default Card;
this is the picture of my problem
as you can see in the picture, the values change every time I click but the cards' color stay the same. however, it will work if I change the class based component into non class based component and set the style in render() instead of constructor, but I want to have a class component so I can pass the card I click to parent component.
Is onClick triggering something else as well? Otherwise, don't see what would change the card's values, since the onClick is just logging.
Assuming the card prop is somehow changing correctly, I believe your issue is that your card prop is updating, but the state is set in the constructor and never updated.
Rather then setting a style value in state, I would just change to calculating style in render.
render() {
const {r,g,b} = this.props.card
const style = {
width: '100px',
height: '100px',
display: 'inline-block',
backgroundColor: `rgb(${r},${g},${b})`
}
return (
<div style={style}>
<button onClick={this.onClick}>card test</button>
</div>
)
}
You generally do not what to keep state that is easily derived from props to avoid situations like this.
Related
i have read and practice with a tutorial but i have tried to make something else and i can t. i explain:
in my app i have have two component <ColoredBlock /> whose code is:
class ColoredBlock extends React.Component {
constructor(props) {
super(props);
this.changeColor = this.changeColor.bind(this);
this.state = {
color: 'red'
};
}
changeColor() {
const newColor = this.state.color === 'red' ? 'blue' : 'red';
this.setState({
color: newColor
});
}
render() {
return (
<div ref={this.maref} className="App-headers" style={{ height: '200px', width: '200px', backgroundColor: this.state.color}}>
<ChangeColorButton clickHandler={this.changeColor} currentColor={this.state.color}></ChangeColorButton>
</div>
)
}
}
export default ColoredBlock;
Each component <ColoredBlock /> has a button as a child to modify the background color and all is working fine but
i have created an external button. This button is not a parent and not a child of my component
i d like , when i click on my button modify the background of one of my element but i cant have access to my element... i know that getElementById doesn t work and i have tried with 'ref' but i can t. Some helps please?
You have to define color state and function to change this state somewhere in parent component of both ColoredBlock and your button and pass it down as props.
It might look ugly thought. That's when redux and all that stuff comes in handy. Also you can use React Context
I feel like this is a simple issue caused by my lack of experience with react, forgive me if I've over-complicated it.
Using npm 'react-youtube', I am trying to call event.target.pauseVideo() on the Video component whenever a specific parent state changes. I have a button which toggles the video component's div display to 'none' or 'block' when clicked, I want this button to also pause or play the video without having to re-render the Video component. I can call event.target.pauseVideo() inside the provided _onReady(){} or _onStateChange(){} with no issues, however I want it to be triggered when I press a button, not on either of those triggers.
I've tried creating my own method in the Video component which calls event.target.pauseVideo(), however I do not know how to trigger this from the parent (I think this is doable using refs, but everywhere I read says refs should not be used 99% of the time.) I've also tried passing event.target.pauseVideo() to the component from the parent, but this seems to try to use an event or target from the parent which doesn't exist instead of the Video component's.
Parent:
class Window extends React.Component {
constructor(props){
super(props)
this.state={
currentDisplay: 1,
isPaused: 0,
}
}
renderVideo(isPaused){
return <Video isPaused={isPaused}>;
}
render() {
return (
<div className='window'>
<div className = 'vid'>
{this.renderVideo(this.state.isPaused)}
</div>
<div className = 'PauseButton'>
<Pause handleClick={() => {this.togglePause()}}/>
</div>
</div>
);
}
}
togglePause() just changes the pause state from 0 to 1 and vice versa
Pause button Component:
class PauseButton extends React.Component{
render(){
return(
<button onClick={() => {this.props.handleClick()} }>
Pause
</button>
)
}
}
Video Component:
class Video extends React.Component{
_pause(event, isPaused){
if(isPaused = 1){event.target.pauseVideo()}
}
_onReady(event) {
//event.target.pauseVideo()
}
render(){
const opts = {
height: '390',
width: '640',
playerVars: { // https://developers.google.com/youtube/player_parameters
autoplay: 1,
}
}
return(
<YouTube
videoId= {'21X5lGlDOfg'}
opts={opts}
onReady={this._onReady}
onStateChange={this._onStateChange}
/>
)
}
}
Currently, the '_pause()' method in the video component is never triggered, but I would like it to be triggered whenever the pause button is clicked.
The code above plays the video without issues, however I am looking for a way to trigger the _pause() method in the Video component without having to re render the component.
Created a code sandbox with Video gettign paused when clicking pause button. Achieved using React Hooks.
https://codesandbox.io/s/elegant-cerf-0os7t
In App.css, I have
.theme {
color: green;
}
And I have className="theme" scattered in multiple components.
Is there a way to change the theme color from green to blue on an event?
If not, how should I design my code?
Well, You can create 2 classes named .blue-theme and .green-theme
Whenever, some event occurs,
onClick = (themeCol) => {
this.setState({theme:thmeCol})
}
render(){
return(
<button onClick={()=>onClick('blue-theme')}>Blue theme</button>
<button onClick={()=>onClick('green-theme')}>Green theme</button>
<div className={this.state.theme}> Sample </div>
)
}
You can pass the value of theme.
you can try
const themeClass = "";
if (event-as-wanted){
themeClass="theme";
}
className={themeClass}
also you can use style insted of className in same file
const theme ={
color: '';
};
style={theme}
and change it with events like
if (event-as-wanted){
theme.color = "green";
}
You can conditionally render the <style/> tag to override style definition for the class in the whole document.
class App extends React.Component {
state = {
red: true,
}
render() {
return (
<div>
<div className="foo">Foo</div>
<button onClick={() => this.setState({ red: !this.state.red })}>
Toggle Red
</button>
{this.state.red && <style>{".foo { color: red }"}</style>}
</div>
);
}
}
Keep in mind that inside JSX tags, curly brackets will be picked up by the interpreter and may break the parser. To avoid that, you should put your CSS inside a string like in the example above.
Adding a <style/> tag to CSS document will override any equally specific CSS rules that came before that. Once the condition is no longer met, the style tag will be removed and the original styling will be restored.
in react.js just set the state of color to whatever and on a click event toggle the color
class App extends React.Component {
constructor(props) {
super(props);
this.state = {color: green};
this.changeColor = this.changeColor.bind(this);
}
changeColor() {
const newcolor = this.state.color == green ? blue : green;
this.setState({ color: newcolor});
}
render() {
return (
<div class="theme" style={{color: this.statecolor}}>
<button onClick={this.changeColor}>
</button>
//put all html withing the parent DOM of element with class theme accordingly or it wont render.
</div>
);
}
Make two class, .green-theme{
color:'green'} and similarly, blue theme.
Mantain a REDUX STATE, CURRENT_THEME. Upon event fire, change the redux state accordingly and everywhere, where you want to use CURRENT_THEME, use it using mapStateToProps.
I would rather try to use almost pure CSS solution:
in App.css
#App.first-theme .theme { color:green; }
#App.second-theme .theme { color:blue; }
in App's render:
<div id="App" className={this.state.currentTheme}>
<AnotherComponent1 />
<AnotherComponent2 />
</div>
All you need to do is to change this.state.currentTheme appropriately. You can even use prop injected from the redux.
Almost all other solutions posted here have the same flaw: you have to adapt all your components to use the theme. Using this solution, you are able to change app's appearance without additional code in your components.
Trust me, injecting the same property from redux store/react context for every component will give you headaches and a lot of unnecessary code.
You should also try to avoid generating additional <style> tags - you will end up having plenty of !important and HTML, logic, and CSS in one file. What a mess! Imagine, what would happen if you would like to use SCSS in the future...
I have a component, let's say it looks like this:
return(
<div id="container"></div>
)
From the beginning it's background image is already set, let's say
#container{
background-image: url('./assets/container.jpg');}
Now I want to add another element inside the container div that will have onClick event firing function, that will do other things + changing the parent's background-image. Dummy code would be:
handleOnClick(){
doOtherStuff();
document.getElementById('container').style.backgroundImage = "url('./assets/container2.jpg')"}
return(
<div id="container">
<div onClick={()=> handleOnClick()}
</div>
)
Problems are:
It doesn't work, it changes background to blank screen,
After I leave the component and go back to it, it reverts to the old background. Is there any way to avoid that without having the background linked with state? I already have a lot of things in store and it will start to get messy real soon if I start adding more styles to it.
This is doable by giving your child the ability to change the state in your parent and holding that logic there. Also, it's much better to control your background shift by using this.setState. Just make it a boolean that controls which CSS id to use.
class Parent extends Component {
constructor() {
super()
this.state = {
defaultBackground: true
}
}
toggleChildBackground() {
const newBackground = !this.state.defaultBackground
this.setState({defaultBackground: newBackground})
}
render() {
return (
<div>
<Child
defaultBackground={this.state.defaultBackground}
toggleChildBackground={this.toggleChildBackground.bind(this)}
/>
</div>
)
}
}
class Child extends Component {
handleClick() {
this.props.toggleChildBackground()
}
render() {
return (
<div id={this.props.defaultBackground ? 'id1' : 'id2'}>
<button onClick={this.handleClick.bind(this)}>
change background
</button>
</div>
)
}
}
Is it good to just specify className for element so i could find it later in the DOM through getElementsByClassName for manipulations?
Adding a class to find the DOM element? Sure you can do that, but refs are probably the better solution.
Manipulating the DOM element? That's an absolute no-go. The part of the DOM that is managed by React should not be manipulated my anything else but React itself.
If you come from jQuery background, or something similar, you will have the tendency to manipulate element directly as such:
<div class="notification">You have an error</div>
.notification {
display: none;
color: red;
}
.show {
display: block;
}
handleButtonClick(e) {
$('.notification').addClass('show');
}
In React, you achieve this by declaring what your elements (components) should do in different states of the app.
const Notification = ({ error }) => {
return error
? <div className="notification">You have an error</div>
: null;
}
class Parent extends React.Component {
state = { error: false };
render() {
return (
<div>
<Notification error={this.state.error} />
<button onClick={() => this.setState({ error: true })}>
Click Me
</button>
}
}
The code above isn't tested, but should give you the general idea.
By default, the state of error in Parent is false. In that state, Notification will not render anything. If the button is clicked, error will be true. In that state, Notification will render the div.
Try to think declaratively instead of imperatively.
Hope that helps.
When using React, you should think about how you can use state to control how components render. this.setState performs a rerender, which means you can control how elements are rendered by changing this.state. Here's a small example. I use this.state.show as a boolean to change the opacity of the HTML element.
constructor(props) {
super(props)
this.state = {
show: true
}
}
handleClick() {
this.setState({show: false})
}
render() {
const visibility = this.state.show ? 1 : 0
return (
<button style={{opacity: visibility} onClick={() => this.handleClick()}>
Click to make this button invisible
</button>
)
}