Need to use react hooks to display a component based on button - reactjs

So I have multiple components and a list of buttons. When I hit a button, I want to use reacthooks to display the corresponding component in {displayComponent}. I only want one component displaying at a time (so if you hit another button it will replace whatever was there previously).
Can someone tell me where i've gone wrong? This isn't working (it's just displaying all three components and the visibility doesn't change). My idea was to have the component display based on if displayComponent matched it's id.
How can I fix it and is there are more efficient way to accomplish this?
import Component1 from "./components/comp1";
import Component2 from "./components/comp2";
import Component3 from "./components/comp3";
function ComponentSelection() {
let [displayComponent, setDisplayComponent] = useState(null);
return(
<Button onClick={setDisplayComponent = "comp1">Click to display component 1</Button>
<Button onClick={setDisplayComponent = "comp2"}>Click to display component 2</Button>
<Button onClick={setDisplayComponent = "comp3"}>Click to display component 3</Button>
{displayComponent}
<Component1 id='comp1' display={displayComponent === 'comp1'} />
<Component2 id='comp2' display={displayComponent === 'comp2'} />
<Component3 id='comp3' display={displayComponent === 'comp3'} />
)
}
export default ComponentSelection

You misunderstood what hooks are. The second element in the returned array is a function to set it. Try this instead:
<Button onClick={() => setDisplayComponent("comp1")}>Click to display component 1</Button>

Related

How to exchange / switch a prop on the click of a button in NextJS?

I have a video player component in NextJs that is populated with video links through a {videoLink} prop:
<ReactPlayer playing={true} controls={true} muted={true} loop={true} width="100" height="100"
url={videoLinkDeep} poster="images/330163_C2B_Clean.png"> </ReactPlayer>
The data being passed into the component consists of several different possible link props such as {videoLinkLong} or {videoLinkShort}.
The preset {videoLinkDeep) portion of the URL is now supposed to be exchanged through another video link prop such as {videoLinkLong} on the click of a button. How can I achieve this given that I start with a:
<button className="bg-black">Preview Length</button>
Only?
First of all, use the useState hook for the url.
const defaultVideoLink = "Default Link";
const longVideoLink = "Long Link";
const shortVideoLink = "Short Link";
const [videoLink, setVideoLink] = useState(dafaultVideoLink);
Then, depending on how you want your UI to be, you can use setState to change the url. Lets say you use three different buttons,
<button onClick={() => setVideoLink(defaultVideoLink)}>View Default Video</button>
<button onClick={() => setVideoLink(longVideoLink)}>View Long Video</button>
<button onClick={() => setVideoLink(shortVideoLink)}>View Short Video</button>
Finally, your react player component will be as follows:
<ReactPlayer {...props} url={videoLink}></ReactPlayer>
You can even do a dropdown or a menu component for the UI using some libraries, but in any case, the logic will be same. Let me know if you need any further help!
Use the hook useState.
Examples and documentation available: https://reactjs.org/docs/hooks-state.html

React toggling between clickable words that pull up <Elements/>

Somewhat new to React.
I want to be able to toggle between React elements CreateUser, EditUser, and ListUser.
It would be great to have a clickable text that when selected pulls up that element and its
corresponding stuff. In the case of Create its a field with a save button.
What is the best way to have my CrudSelector class list all three texts, make them clickable and pull up the stuff inside toggling to the selected one at a time?
Welcome. Always a good idea to share code with your question.
You'll want to use some kind of state which tells your parent component which child component to show. Kind of like this in your React functional component:
const [ featureToShow, setFeatureToShow ] = useState('list')
return (
<>
{/* Show some buttons to change the state */}
<button onClick={() => setFeatureToShow('list')}>Show User List</button>
<button onClick={() => setFeatureToShow('create')}>Create User</button>
<button onClick={() => setFeatureToShow('edit')}>Edit User</button>
{/* Depending on what is in the state show that component */}
{ featureToShow === 'list' ? <ListUser /> : null }
{ featureToShow === 'create' ? <CreateUser /> : null }
{ featureToShow === 'edit' ? <EditUser /> : null }
</>
)
In reality you'll probably want to enable clicking on the user's name in ListUser to show the EditUser 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.

Problem Too many re-renders.Try to render components in connection with a button and state hooks

I'm new to react and face following problem:
I have two buttons and want to render two different components. Pressing one button should set a variable true via state hook and the first component should be shown, on the other side the variable for the other component should be set to false. With this logic I try to render either one or the other component.
With this setup I get following Error Message:
Too many re-renders. React limits the number of renders to prevent an infinite loop.
I guess the solution is simple but I cannot see the why this causes a problem.
Thx for any help!
Here a simplified version of the relevant code:
import { Button } from "semantic-ui-react";
import React, { useState } from "react";
const App = () => {
const [showAggregated, setshowAggregated] = useState(true);
const [showDetailed, setshowDetailed] = useState(false);
return (
<div>
Test
<Button.Group>
<Button
size="mini"
onClick={(() => setshowAggregated(true), setshowDetailed(false))}
>
Aggregated Visualization{" "}
</Button>
<Button.Or />
<Button
size="mini"
onClick={(() => setshowDetailed(true), setshowAggregated(false))}
>
Detailed Visualization
</Button>
</Button.Group>
{/* Second Part of Page if Aggregated Component */}
{showAggregated && <div>Aggregated</div>}
{/* Second Part of Page if Detailed Component */}
{showDetailed && <div>Detailed</div>}
</div>
);
};
export default App;
onClick={(() => setshowDetailed(true), setshowAggregated(false))}
You are using Comma Operator above, which evaluates each of its operands.
In your case you have 2 operands: () => setshowDetailed(true) and setshowAggregated(false), so basically what happens is that each time the component is rendered, the second operand (setshowAggregated(false)) is called, which re-render the component which eventually ends up in an infinite loop.
What you really wanna do is this (an event handler that calls both functions):
onClick={() => {
setshowDetailed(true);
setshowAggregated(false));
}}
Same thing for the second button.

Non-component onclick trigger React Component update

If I have some buttons which were not React components, e.g. for an add to basket:
<button value="1">Buy Product 1</button>
<button value="2">Buy Product 2</button>
<button value="3">Buy Product 3</button>
And I have a React component that stores the values of buttons clicked (e.g. a basket view), how would I get the data from the buttons clicked into the react component? Would an event listener like this for each button suffice?: https://facebook.github.io/react/tips/dom-event-listeners.html) I'm trying to do this all client side, as the buttons wil be rendered server side on pageload.
Thanks in advance!
EDIT:
In response to a suggestion below, here's a bit more background information:
The issue is that the buttons are generated in PHP and aren't repeated one after the other. We have a pre-existing system of twig template'd product listings, so the only real solution is to keep the buttons rendered as is, and use a react component for the basket view. So a click of a pre-existing non-react button needs to pass the value (product sku/id) into the react component to update the basket
You can try something like this :
class App extends Component {
constructor(props) {
this.state = {
basket: []
}
this.addItemToBasket = this.addItemToBasket.bind(this);
}
addItemToBasket(e) {
let item = e.value;
let basket = this.state.basket;
basket.push(item);
this.setState({basket: basket});
}
render() {
return(
<button value="1" onClick={this.addItemToBasket(this)}>Buy Product 1</button>
<button value="2" onClick={this.addItemToBasket(this)}>Buy Product 2</button>
<button value="3" onClick={this.addItemToBasket(this)}>Buy Product 3</button>
<Basket items={this.state.basket} />
}
}
}
this will call addItemToBasket when each button is clicked and then add that item to the basket and set the state with the new basket. Then you can pass the state as a prop to the component where you want to display what is added.

Resources