NextJS: Replace - reactjs

I have a div in a Next JS application that displays the currency and price of a product once a user enters a product page.
<div className="flex">
<Image src={EuroCurrency} alt="Euro Sign} />
<h1 className="ml-5>9.800,00</h1>
</div>
Through an onClick event on a button, I want to exchange this div with another, evenly formatted but contextually different, div.
<div>
<Image src={DollarCurrency} alt="Dollar Sign} />
<h1 className="ml-5>9,500.00</h1>
</div>
This div would need to be hidden until the user clicks the aforementioned button.
I'm aware that this would be achieved through a state - but I'm uncertain on how to hide (and exchange) a complete div.

this is how you can use conditional rendering and useState together to switch the component
import React from 'react'
export default function App() {
const [toggle, setToggle] = React.useState(false);
return (
<div className="App">
{toggle ? ( <div >
<h1 >9.800,00</h1>
</div>): (<div><h1>9,500.00</h1></div>)
}
<button onClick={()=>{setToggle(!toggle)}}>Toogle</button>
</div>
);
}
Here you need to change the conditional rendering that suits you like
{toggle ? ( COMPONENT 1 ): ( COMPONENT 2 )}

I'm making a few guesses at what you're asking, but hopefully this example helps.
This is an example of a functional component that uses state to switch between rendering euro and dollars components:
import { useState } from 'react';
function MyAwesomeComponent(){
// expected state values are "dollar" or "euro"
// if you use TypeScript, you can enforce that,
// but I'm just a TypeScript shill :P
// "dollar" is the initial state
const [currency, setCurrency] = useState("dollar");
return(
<div className="flex">
{ currency === "dollar"
? <Image src={DollarCurrency} alt="Dollar Sign" />
: <Image src={EuroCurrency} alt="Euro Sign" />
}
<h1 className="ml-5">9.800,00</h1>
<button onClick={
() => currency === "dollar" ? setCurrency("euro") : setCurrency("dollar")
}
>
Click to Switch Currency
</button>
</div>
)
}
There are plenty of other ways to do it. But notice how, instead of having the whole div rendered conditionally and duplicating code, I just render the specific Image component conditionally. Depending on your use case, you could conditionally render divs instead, any component can go in the two slots of the terney expression.

Related

How can I render one component conditionally twice and not lose internal states/unmounts?

I have one component which needs to be rendered conditionally. Renders the same component with different styles. So, I did like this
import ComponentToRender from '../../ComponentToRender'
const Main =()=> {
const [expand,setExpand] =useState(false)
return (
<div>
{!expand && <ComponentToRender {...someProps} />}
{expand && <div>
<ComponentToRender {...otherProps} />
</div>
}
<button onClick={()=>setExpand(pre => !pre)}>Expand</button>
</div>
)
}
For the above code, I get what I want in terms of UI. But, all the internal states are lost. I must render two components like that and keep the internal states. Is that possible to do that in React?
You can achieve this by keeping the component rendered unconditionally and hiding it with CSS.
You get to preserve Component‘s state for free along with the DOM state (scroll, focus, and input position). However, this solution has drawbacks, too:
You mount the component on startup, even if the user never accesses it.
You update the component even when it’s invisible.
import ComponentToRender from "../../ComponentToRender";
const Main = () => {
const [expand, setExpand] = useState(false);
return (
<div>
<div style={{ display: expand ? null : "none" }}>
<ComponentToRender {...someProps} />
</div>
<div style={{ display: !expand ? null : "none" }}>
<div>
<ComponentToRender {...otherProps} />
</div>
</div>{" "}
<button onClick={() => setExpand((pre) => !pre)}>Expand</button>
</div>
);
};
The reconciliation algorithm is such that when on next render you move from one component to component of different type (assuming they have same spot in component hierarchy), instance of old component is destroyed.
Since you have <ComponentToRender/> and another one is <div><ComponentToRender/></div>, they are different components (because one is inside a div).
Read about reconciliation.
What you can do is move the state of ComponentToRender to Main and pass it as props. Now even if the component unmounts the state will not be lost.

How to NOT render/ hide a React component when no prop is passed?

TLDR: Cannot figure out why component is still being rendered while no props are passed.
So I have been building a NextJS application, and I have this banner component that is shown on every page of my website. It has some header text, buttons and an image:
const Banner = (props) => {
return (
<div className={bannerStyles.wrapper}>
<div className={classnames(bannerStyles.banner, "wrap", "center")}>
<div className={bannerStyles.banner_left}>
<h1>{props.header}</h1>
<div className={bannerStyles.button_wrapper}>
<div className={bannerStyles.button}>
<Button>{props.button || null}</Button>
</div>
<div className={bannerStyles.button}>
<Button>{props.scnd_button || null}</Button>
</div>
</div>
</div>
<div className={bannerStyles.banner_right}>
<Image src={props.image} alt=""></Image>
</div>
</div>
</div>
);
};
Inside of this, as you can see I have two Button components (The MDEast thing is an arrow icon):
const Button = ({children}) => {
return (
<div className={buttonStyles.button}>
<Link href="/"><a>{children} <MdEast /></a></Link>
</div>
)
}
Now I want the option that if no prop is passed, that the Button component(s) do(es) not render/ is hidden from the page, so that it is optional per page. Yet the Button does still render, even though I am not passing any props on my About page. My about page:
const About = () => {
return (
<>
<Banner
header="Hello this is my code"
image={banner_placeholder}
/>
</>
)
}
PS. I am fairly new to React and NextJS, so this might be a beginner mistake, or I am not understanding the fundamentals well enough, but could someone point me in the right direction please?
To conditionally render the button you can use:
props.button && <Button>{props.button}</Button>
When props.button is falsy, then button will not get rendered.

Avoid component update while changing state vaiable

Background
I have a React component which includes further two more components. I component includes a chart(build with react-charts) and the other is a simple input field. I initially make not visible but it become visible when someone clicks icon over there.
Issue, child rerenders when state changes
Now the problem is whenever I toggle this input field it automatically refreshes my graph. In fact when I type into my input field it also refreshes the graph. I think it rerenderes the graph as I update the state variable. I want to stop this behavior. Any suggestions on how can I do this.
Component Screenshot(https://i.imgur.com/zeCQ6FC.png)
Component Code
<div className="row">
<DealGraph ref={this.dealRef} />
<div className="col-md-4">
<div className="row">
<div style={style} className="col-md-12 bg-white border-radius-10 default-shadow">
<h3 className="sub-heading roboto" style={border}>
Create Deals
</h3>
<input
type="text"
name="deal"
className="form-control mgt-30"
value="Deal One"
readOnly
/>
<button
type="button"
onClick={this.showAddBlock}
style={button}
className="golden-button create-deal-button"
>
<i className="fa fa-plus"></i>
</button>
{addDealStatus ? (
<div className="col-md-12 add-deal-box pd-0-0">
<input
type="text"
className="form-control mgt-30 mgb-10"
name="add-deals"
placeholder="Add Deals"
/>
<button type="button" className="golden-button flex all-center">
Add
</button>
</div>
) : null}
</div>
</div>
</div>
</div>
Toggle function
showAddBlock=() => {
this.setState({addDealStatus:!this.state.addDealStatus})
}
use PureComponent
To stop a child component rerendering from it parent you should make the child a pure component.
import React from 'react';
class DealGraph extends React.PureComponent { // notice PureComponent
render() {
const { label, score = 0, total = Math.max(1, score) } = this.props;
return (
<div>
/* Your graph code */
</div>
)
}
}
Use the { pure } HOC from Recompose
You can use a functional component that is wrapped in the pure HOC from recompose
import React from 'react';
import { pure } from 'recompose';
function DealGraph(props) {
return (
<div>
/* Your graph code */
</div>
)
}
export default pure(DealGraph); // notice pure HOC
A quick solution would be to move the input to an own component.
A more sophisticated solution is adapting the shouldComponentUpdate function in your DealGraphcomponent like stated here React: Parent component re-renders all children, even those that haven't changed on state change
By Default while rendering every component react checks for shouldComponentUpdate .React Components dont implement shouldComponentUpdate by default.So either we can implement a shouldComponentUpdate. Or Make the child class as a pure component.

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.

My Toaster component is not creating multiple toasters on multiple clicks. Reactjs

I have made a toaster component which is only rendering 1 toaster on 1 or multiple clicks, but I need a component the renders multiple toasters on multiple clicks.
This is my Toaster Component.
import React, {Component} from 'react'
import '../stylesheets/adminlte.css'
ToastMsg = (props) => (
<div className=" snackbar" key={props.idx}>
<div className="card-header">
<h3 className="card-title">Toast</h3>
</div>
<div className="card-body">{props.message}</div>
<div className="card-footer"/>
</div>
)
createtoaster = () => {
if (this.state.show) {
return this
.state
.message
.map((msg, idx) => <ToastMsg idx={idx} message={msg}/>)
} else {
return null;
}
}
render() {
return (
<div className="col-md-2 offset-md-9">
<button className="btn btn-primary" onClick={this.handleOpen}></button>
{this.createtoaster()}
</div>
)
}
I am providing this.state.message from another component and passsing it via props. I cannot use any Library as per the requirement so if anyone can help me with this, It is appreciated. Also feel free to point out any mistakes in my code.
missing array element 'picker': < div className="card-body">{this.state.message [i] }
I would use map, too ... with key property for each item.
Are you sure you're receiving array with more elements ?

Resources