sending props render component separately one more time - reactjs

CalculateResults.js and ScoreBox.js are class components.
I send the result i wanna see in ScoreBox form CalculateResults like this:
CalculateResults.js
render(){
return(
<ScoreBox calculate={this.state.calculate} />
)
}
and i get this props in ScoreBox like this:
ScoreBox.js
render(){
return (
<div className="scoreBox d-flex">>
<div>
<p>score</p>
<h2>{this.props.calculate}</h2>
</div>
</div>
);
}
my problem is that it doesn't update scorebox, it renders another scorebox next to the previous one and shows the result there.
The whole story is like this: Scorebox component exists then When i click a button in UserMove.js a boolean called onlyChooseOne becomes true and i send some props to CalculateResults.js like this:
UserMove.js
render(){
return(
<div>
{
!onlyChooseOne
&&
<CalculateResult number={randomNumber} userChoice={userChoice} />
}
)
</div>
}
How should i fix it?

Related

React Button Click Hiding and Showing Components

I have a toggle button that show and hides text. When the button is clicked I want it to hide another component and if clicked again it shows it.
I have created a repl here:
https://repl.it/repls/DapperExtrasmallOpposites
I want to keep the original show / hide text but I also want to hide an additional component when the button is clicked.
How to I pass that state or how do I create an if statement / ternary operator to test if it is in show or hide state.
All makes sense in the repl above!
To accomplish this you should take the state a bit higher. It would be possible to propagate the state changes from the toggle component to the parent and then use it in any way, but this would not be the preferred way to go.
If you put the state in the parent component you can use pass it via props to the needed components.
import React from "react";
export default function App() {
// Keep the state at this level and pass it down as needed.
const [isVisible, setIsVisible] = React.useState(false);
const toggleVisibility = () => setIsVisible(!isVisible);
return (
<div className="App">
<Toggle isVisible={isVisible} toggleVisibility={toggleVisibility} />
{isVisible && <NewComponent />}
</div>
);
}
class Toggle extends React.Component {
render() {
return (
<div>
<button onClick={this.props.toggleVisibility}>
{this.props.isVisible ? "Hide details" : "Show details"}
</button>
{this.props.isVisible && (
<div>
<p>
When the button is click I do want this component or text to be
shown - so my question is how do I hide the component
</p>
</div>
)}
</div>
);
}
}
class NewComponent extends React.Component {
render() {
return (
<div>
<p>When the button below (which is in another component) is clicked, I want this component to be hidden - but how do I pass the state to say - this is clicked so hide</p>
</div>
)
}
}
I just looked at your REPL.
You need to have the visibility state in your App component, and then pass down a function to update it to the Toggle component.
Then it would be easy to conditionally render the NewComponent component, like this:
render() {
return (
<div className="App">
{this.state.visibility && <NewComponent />}
<Toggle setVisibility={this.setVisibility.bind(this)} />
</div>
);
}
where the setVisibility function is a function that updates the visibility state.

React/Redux Form ReRender Method

I would like to insert advertisement block (such as Google Adsense) inside of items list. I am using the react-redux & react-connect. Even if I need to refresh the feed and rerender, I would like to run the render of ad-block div only one time. Is there any way we can do this?
render(){
const { feed } = this.props;
return(
<div>
<div class="ad-block"><!-- Need To Render one time --></div>
<div class="items">
{_.map(feed.data, item => {
return <div class="item">.......</div>
})}
</div>
<div class="ad-block"><!-- Need To Render one time --></div>
);
}
How about to split it in 3 components?
export const Something = () => (
<>
<AdBlock>
<Feed>
<AdBLock>
<>
);
And connect Feed separately through Redux.

ReactJS- Only latest line of text is appearing in web page

I have this class function
class Fact extends React.Component {
render() {
return (
<img src="Logo.png"/>,
<center><p>FACT</p></center>,
<h1>Hello</h1>
)
}
}
export default Fact;
When running my localhost server, only "Hello" appears on the webpage. The logo doesn't appear, or the text message "FACT". Only "Hello" appears...How do I fix this?
Im trying to fit in 3 paragraphs as text to appear on my website, along with the logo. What's the best practice for this, rather then spam ?
You need to wrap the render output within a "root element", such as a <div> element to ensure that reactjs renders all the contents of the Fact component as you are expecting.
See the comments and code below, showing how to correct the error:
class Fact extends React.Component {
render() {
return (
<div> {/* Add <div> opening tag here */}
<img src="Logo.png"/>,
<center><p>FACT</p></center>,
<h1>Hello</h1>
</div> {/* Add </div> closing tag here */}
)
}
}
Note also that </h1> is missing the > in your question. This has been corrected in my answer
In React, if you're rendering multiple nodes (e.g. img, center, h1), you need to nest them under one parent node, e.g. <div>. That is, you can only return one top level node from your render function.
So:
class Fact extends React.Component {
render() {
return (
<React.Fragment>
<img src="Logo.png" /> ,
<center>
<p>FACT</p>
</center>
<h1>Hello</h1>
</React.Fragment>
);
}
}
Note that React.Fragment could also be something like a div.

Changing background-image after onClick event in ReactJS

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>
)
}
}

Calling a function for ALL child components

I have 3 components. They parent layout, a select box, and a panel this is generated x times from some data.
<Layout>
<Dropdown>
<Panel>
<Panel>
<Panel>
I'm trying to make it so when the select value changes, the contents of each panel changes. The changes are made by doing some math between the new select value, and data that is stored in the panel component. Each panel has different data.
Layout.js
updateTrueCost(selected){
this.refs.panel.setTrueCost
}
render(){
return (
<div>
<div class="row">
Show me the true cost in
<CurrencyDrop currencyChange = {(e) => this.updateTrueCost(e)} data = {this.state.data} />
</div>
<div class="row">
{this.state.data.map((item, index) => (
<Panel ref="panel" key = {index} paneldata= {item} />
))}
</div>
</div>
);
}
Panel.js
setTrueCost(selected){
//Do some math
this.setState({truecost: mathresult})
}
render(){
return(
<div>
{this.state.truecost}
</div>
)
}
CurrencyDrop.js
onHandelChange(e){
this.props.currencyChange(e);
}
render(){
return(
<Select
onChange={this.onHandelChange.bind(this)}
options={options} />
)
}
The current result is only the last panel updates when the select changes. I'm guessing I'm doing something wrong with the ref handling, but I must not be searching the right terms because I can't find any related questions.
Instead of calling ref's method use React build-in lifecycle methods.
class Panel extends React.Component {
componentWillReceiveProps (newProps) {
// compare old and new data
// make some magic if data updates
if (this.props.panelData !== newProps.panelData) {
this.setState({trueCost: someMath()});
}
}
render () {
return <div>{this.state.trueCost}</div>
}
}
Then just change input props and all data will be updated automatically.

Resources