So I have this div that switch from one component to another by changing the state after clicking on a button.
{ !showForm ? (
<div className={styles.showTicketContainer}>
<div className={styles.showTicketBox}>
//some code for UI
</div>
<div className={styles.whitelistBox}>
<Button className={styles.whiteListToggleButton} shape="round" onClick={() => setShowForm(() => true)}>Whitelist</Button>
</div>
</div>
) : (
<InputEmail /> // render another component within this div after clicking the whitelist button
)}
So to visualize this is from this to this. And I would like to add one button on the email page so that I can go back to the first page.
Do I still use the same way which is:
{ !showForm ? (
//some UI code
) : (
<someComponent/>
)}
or is there any better way to do this.
you can use this:
const history = useHistory();
history.goBack();
If you're creating pages, I definitely suggest using React Router or a similar library to handle this. With React Router, you can easily "back" out to the previous page, and even the "back" button in the user's browser will work, instead of having to click a button.
This code will work.
Add them wherever required..
import { useHistory } from "react-router-dom";
function demo () {
let history = useHistory();
const goToPreviousPath = () => {
history.goBack()
}
return (
<div>
<Button
onClick={goToPreviousPath}
>
Back
</Button>
</div>
):
}
Related
I am trying to make a hide/show navbar in ReactJS.
But on the first click I am getting this error and its working fine after the first click.
Note: Its twice and i have no idea why
Here is my code and its only working (after first error) when
setMenu(!menu);
is before
nav.classList.toggle("nav-open");
otherwise the error just keeps coming.
export default function Navbar() {
const [menu, setMenu] = useState(true);
const nav = document.querySelector("nav");
const openNav = () => {
setMenu(!menu);
nav.classList.toggle("nav-open");
};
return (
<nav id="nav-wrapper">
<header className="nav-header">
<div
className="arrow-btn"
onClick={() => {
openNav();
}}
>
{menu ? (
<Icon.HiChevronDoubleLeft size={20} className="arrows" />
) : (
<Icon.HiChevronDoubleRight size={20} className="arrows" />
)}
</div>
<img src={Profiledp} alt="." />
<p className="name">Naman Pokhriyal</p>
</header>
</nav>
This isn't the right way of doing this in React in the first place. You're already using the menu state value to determine if the menu is open is not, so why not continue to use the menu state value to determine if the menu is open or not? Something like this:
const openNav = () => {
setMenu(!menu);
};
return (
<nav id="nav-wrapper" className={menu ? "nav-open" : ""}>
// etc.
);
Basically any time you're trying to directly manipulate the DOM in React, take a step back and try to find a way to manage that via state instead. Direct DOM manipulation in React almost always leads to bugs unless you really know what you're doing under the hood in the framework.
I'm new with React and Next.js, I'm creating a timeline, the timeline has colored bars which if pressed, the page shows a div below with info about each bar.
I managed to make the content below appear and disappear with useState hook so the content of each bar doesn't stack, I'm using an animated tag "Section" and only the first time I press any bar, the content is animated, the rest appears statically, I'm wondering if I can use something like the useEffect hook to maybe re-render each content div so the animation appears every time you click each bar, also to erase the last loaded div so doesn't stack on browser memory, I hope I explained myself I started with React 2 days ago, and thank you for your time.
Example reduced code:
//useState hook
const [content, setContent] = useState(null);
//Timeline section
<div>
<Bar1 onClick={() => setContent(BarContent_1)}/>
<Bar2 onClick={() => setContent(BarContent_2)}/>
</div>
//Content display
<div>
{content}
</div>
//Content of each bar, (<Section> div has the animation)
const BarContent_1 = () => {
return (
<Section>
Content of bar 1
</Section>
)
}
const BarContent_2 = () => {
return (
<Section>
Content of bar 2
</Section>
)
}
you can use useState for that to toggle classList on element here is example below what I do, in your project I don't know what you do but I will come up with card example first as your default value set state to false in card component and when you will click the button toggle that boolean false to true
like that () => setState(!state) it will always set the value of opposite state
when you will change state component always re-renders and checks the state, and you will make like that on more info div, if that state is true show more-info active that means your div will be displayed
and if it is false it will be dissapeared
const Card1 = () => {
const [showMore, setShowMore] = useState(false)
return (
<div className="card">
<div>Daniel</div>
<button onClick={() => setShowMore(!showMore)}>Show More</button>
<div class={showMore ? "more-info active": "more-info"}>This is more info Daniel</div>
</div>
)
}
also here is my css what I do
.more-info{
opacity: 0;
transition: 0.5s ease;
}
.active{
opacity: 1
}
in start thats good to make stuff like that but I would recommend you to use array objects for that to .map() components and make toggling animations on that, good luck
also quickly I made working example on sandbox
#callmenikk gave me an idea to use a conditional to render my styled div every time the condition met.
Solution:
//useState hook
const [content, setContent] = useState(null);
//Conditional function 'Refresh'
const Refresh = ({children}) => {
const active = content != setContent
if (active) {
return (
<Section>
{children}
</Section>
)
}
}
//Timeline section
<div>
<Bar1 onClick={() => setContent(BarContent_1)}/>
<Bar2 onClick={() => setContent(BarContent_2)}/>
</div>
//Content display and wrapping the content in my Refresh function
<Refresh>
{content}
</Refresh>
//Content of each bar, no need to wrap content in my styled (Section) tag since my Refresh button will
const BarContent_1 = () => {
return (
<div>
Content of bar 1
</div>
)
}
const BarContent_2 = () => {
return (
<div>
Content of bar 2
</div>
)
}
I am using a component that I cannot change directly, but I would like to extend.
import { Button } from '#external-library'
// Currently how the button component is being used
<Button click={() => doSomething()} />
// I would like to add a tabIndex to the button
<Button click={() => doSomething()} tabIndex={0} />
I cannot add an attribute because the component is not expecting a tabIndex. I cannot directly modify the Button component.
How can I extend the <Button /> component so I can add attributes like tabIndex, etc?
I was hoping something like the following would work:
export default class ExtendedButton extends Button { }
// except I'm dealing with functional components
You can't edit custom component implementation without changing its internals.
// You can't add tabIndex to internal button without changing its implementation
const Button = () => <button>Click</button>;
In such cases, you implement a wrapper with desired props:
const Component = () => {
return (
<div tabIndex={0}>
<Button />
</div>
);
};
If the component forwarding ref (also depends to which element it forwarded in the implementation), you can use its attributes:
// Assumption that Button component forwards ref
const Button = React.forwardRef((props,ref) => <button ref={ref}>Click</button>);
<Button ref={myRef}/>
// Usage
myRef.current.tabIndex = 0;
You can access the inner DOM button element using React refs(read here)
most likely the external-lib you use provide a ref prop for the Button component which you use to pass your own create ref
const buttonRef = useRef(null);
<Button ref={buttonRef}/>
Then you can use buttonRef.current to add tabIndex when your data is ready to be populated in like
useEffect( () => {
if(buttonRef && buttonRef.current){
buttonRef.current.tabIndex = 2;
}
}, [props.someProperty] );
When I click on the image I want that it is automatically scrolled to the component which is then displayed. I tried with anchor tags, but it's not working (I believe due to the fact that the component is hidden and at the same time when it is shown it should be scrolled to it ) , useRef - I get the error 'not defined' (I believe same reason as above).
Component is displyed onClick, but it does't scroll to the view-port of the user. Pls help, I'm out of the ideas :/
const WebContent = () => {
const [hidden, setHidden] = useState(false)
return (
<div>
<img onClick={() => setHidden(true)} src={first}/>
<div>
{hidden && <MyComponent/>}
</div>
</div>
)}
Your intuition is probably right that MyComponent is not yet mounted when you try to scroll to it. A simple way to do this would be to have MyComponent scroll itself into view when it mounts, if that's the behavior you're looking for.
const MyComponent = () => {
const ref = React.useRef(null);
useEffect(() => {
if (ref.current) ref.current.scrollIntoView();
}, [ref]);
return (
<div ref={ref}>
NOW YOU SEE ME
</div>
);
};
export default MyComponent;
One (hacky?) idea is add the ref to the surrounding div of the hidden content:
this.scrollHere = React.useRef(null);
...
return (
<div style={{ minHeight: 1 }} ref={this.scrollHere}>
{hidden && <div>My Hidden Component</div>}
</div>
)
Then you can run a function onClick, which sets hidden to true (which by the way is kinda irritating. Maybe just use "shown" as a quick improvement) and also lets the ref scrollIntoView:
const showAndScroll = () => {
setHidden(true);
this.scrollHere.current.scrollIntoView({
behavior: "smooth"
});
};
The minHeight has to be placed on the div since it is at height of 0 first and this messes with the scroll function (it scrolls below the hidden content).
See working example here.
I'm using a library to render a Gantt Chart. This Chart provides an js event to handle a button click. I need to route or render another react component in that event. So... how can i render o route to my component in that event? I'm using react router and meteor.
render() {
gantt.config.buttons_left=["dhx_save_btn","dhx_cancel_btn","dhx_delete_btn"];
gantt.config.buttons_right = ["go_task_btn"];
gantt.locale.labels["go_task_btn"] = 'VER';
gantt.attachEvent("onLightboxButton", function(button_id, node, e){
if(button_id == "go_task_btn"){
var idTask = gantt.getState().lightbox;
//HERE I WAN TO REDIRECT OR RENDER ANOTHER
// REACT COMPONENTE
}
});
return (
<div>
<Toolbar
zoom={this.state.currentZoom}
onZoomChange={this.handleZoomChange}
/>
<div className="gantt-container">
<Gantt
tasks={data}
zoom={this.state.currentZoom}
onTaskUpdated={this.logTaskUpdate}
onLinkUpdated={this.logLinkUpdate}
/>
</div>
{/*<MessageArea messages={this.state.messages}/> */}
</div>
); }}export default App;
You can do this by making a function outside render, put all your code their and call this function in the return.