I have a navbar component, which has a button that transforming me to path (React-Router) "/NEXUM", But, When I'm transformed to NEXUM, i want to change the text of the navbar and the navigation path, so when I click it, it will bring me to a different path, called "/".
const NavBar = () => {
const navigate = useNavigate()
const homeToNavigate = () => {
navigate('/')
}
const Navigation = () => {
navigate('/nexum')
}
return (
<Box sx={{ flexGrow: 1 }}>
<AppBar id="bar">
<Toolbar>
<img onClick={homeToNavigate} className="logo" src={logo}></img>
<Button onClick={Navigation} id='nexumNavigation'> להכנסת קובץ אקסל ישיר </Button>
</Toolbar>
</AppBar>
</Box>
)
}
export default NavBar
This is The nav bar component, The "navBar" component is used in both "HomePage" Component that I'm using and "SpagetiComponent", So as I said, I need the purpose of the button to change, I tried doing it with props, but I was unsuccessful, if you have an idea, please let me know.
let location = useLocation();
<Button onClick={location.pathName==="/NEXUM"?homeToNavigate:Navigation} id='nexumNavigation'>{location.pathName==="/NEXUM"?"go home":"go NEXUM"} </Button>
Related
I have a menu where every menu item is a button and I want to load a specific reactjs component into a specific div without reloading the whole page.
This is the current code, clearly is bad but I don't know where to start fixing it...
...
<Button onClick={this.loadTarget}>
{menuItem.name}
</Button>
...
loadTarget(event) {
document.getElementById("datapanel").innerHTML="abc<TranslationsList />";
}
When I click a menu Item I want to load my div with the value "abc<TranslationsList />". "abc" is displayed but the custom component "TranslationsList" is not and I guess this is normal as the TranslationsList tag is not a HTML tag. But how could I load my component?
I could use links instead of buttons but in this case the question is how could I update the div content with a specific link?
It's hard if you've programmed plain JS before, but you have to forget the "good old JS pattern" in React. I also had a hard time getting used to not using standard JS elements (target, innerHTML, etc.) to solve such a problem.
So the solution in React is to use the framework and your page reload problem will be solved immediately. useState for the state of the component and handlers for the click. My main code looks like this. You can find a working application at Codesandbox.
export default function App() {
const [showComponent, setShowComponent] = useState(false);
const handleButtonClick = (e) => {
setShowComponent(!showComponent);
};
return (
<div className="App">
<h1>
Load specific DIV with a react component without reloading the whole
page
</h1>
<a href="https://stackoverflow.com/questions/74654088/load-specific-div-with-a-react-component-without-reloading-the-whole-page">
Link to Stackoverflow
</a>
<div style={{ marginTop: "20px" }}>
<button onClick={handleButtonClick}>Magic</button>
</div>
{showComponent ? (
<div style={{ marginTop: "20px" }}>
This is the place of your component!
</div>
) : (
""
)}
</div>
);
}
In the first place I wpuld not use vanilla JS syntax on a react app if it is not necessary. i.e: document.getElementById("datapanel").innerHTML="abc<TranslationsList />".
If you are using React you should be managing the State in the component of the DIV, giving the order to make an element appear once the button is clicked.
A simple example can be this:
CodeSandbox
import { useState } from "react";
export default function App() {
const [divState, setDivState] = useState(null);
const divElement = () => <div>I am the element that should appear</div>;
const handleDiv = () => {
setDivState(divElement);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={handleDiv}>Show DIV</button>
<div>{divState}</div>
</div>
);
}
I agree with the answers given above. Since you are already using React, you should take advantage of its features/functionalities. No need to reinvent the wheel.
However, if you are still interested in how to make your current implementation work. You may use renderToString(), which can be imported from ReactDOMServer. Please refer to the following code snippet as an example.
import { renderToString } from 'react-dom/server'
const TranslationsList = () => {
return <div>TranslationsList Content</div>
}
export default function App() {
const loadTarget = () => {
document.getElementById("datapanel").innerHTML=`abc${renderToString(<TranslationsList />)}`;
}
return (
<div>
<button onClick={loadTarget}>Insert Component</button>
<div id="datapanel">Data Panel Holder</div>
</div>
);
}
I have a button named "Open dialog" inside Material-UI Select. If I click on it, a dialog will open. I need to write test cases for that button which is inside Select. Can someone explain me how to do it. I am using snapshot testing and this is the code. The test case is failing as "unable to find data-testid openDialog"
main code:
import * as React from 'react';
import Box from '#mui/material/Box';
import InputLabel from '#mui/material/InputLabel';
import MenuItem from '#mui/material/MenuItem';
import FormControl from '#mui/material/FormControl';
import Select, { SelectChangeEvent } from '#mui/material/Select';
import { Button, Dialog, DialogActions, Typography } from '#mui/material';
export default function BasicSelect() {
const [age, setAge] = React.useState('');
const handleChange = (event: SelectChangeEvent) => {
setAge(event.target.value as string);
};
const [openDialog, setOpenDialog] = React.useState(false)
return (
<Box sx={{ minWidth: 120 }}>
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">Age</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={age}
label="Age"
onChange={handleChange}
inputProps={{'data-testid': 'selectForm'}}
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
<div style={{bottom: 0}}>
<Button variant="contained" onClick={() => setOpenDialog(true)} data-testid="openDialog">open dialog</Button>
</div>
</Select>
</FormControl>
<Dialog open={openDialog} maxWidth={'sm'}>
<Typography>hii all</Typography>
<DialogActions>
<Button onClick={() => setOpenDialog(false)} data-testid="cancel">Cancel</Button>
</DialogActions>
</Dialog>
</Box>
);
}
This is my test code:
import { render, fireEvent, screen, cleanup, waitFor } from '#testing-library/react';
and the test case is
it('Open dialog', async() =>
{
const { container } = render(
<ThemeProvider>
<Demo />
</ThemeProvider>
);
const selectForm = screen.getByTestId('selectForm')
fireEvent.click(selectForm);
const openDialog = await waitFor(() => screen.getByTestId('openDialog'));
fireEvent.click(openDialog);
expect(container).toMatchSnapshot();
});
Thank you.
I am using MUI ToggleButtonGroup component like so:
<ToggleButtonGroup
color="primary"
value={mode}
exclusive
onChange={changeHandler}
fullWidth
className="mt-4"
>
<ToggleButton value="login">Login</ToggleButton>
<ToggleButton value="register">Register</ToggleButton>
</ToggleButtonGroup>
When clicking the 'Register' button, it works fine in the UI. I'd like to get a proper test written with React Testing Library.
Here's what I have:
setup();
heading = screen.getByRole("heading", { level: 2 });
const registerButton = screen.getByRole("button", { name: /register/i });
userEvent.click(registerButton);
expect(heading).toHaveTextContent("Register");
The crux of the issue seems to be that userEvent.click somehow doesn't call the changeHandler. Is there some type of bubbling or something that I need to concern myself with?
Here's a prettyDOM log of the relevant components:
<button
aria-pressed="false"
class="MuiButtonBase-root MuiToggleButton-root MuiToggleButton-fullWidth MuiToggleButton-sizeMedium MuiToggleButton-primary MuiToggleButtonGroup-grouped MuiToggleButtonGroup-groupedHorizontal css-j4p6el-MuiButtonBase-root-MuiToggleButton-root"
tabindex="0"
type="button"
value="register"
>
Register
<span
class="MuiTouchRipple-root css-8je8zh-MuiTouchRipple-root"
/>
</button> <h2
class="MuiTypography-root MuiTypography-h5 css-ag7rrr-MuiTypography-root"
>
Login
</h2>
Add an id to the component:
<ToggleButton id={${data.value}}> {data.label}
test case:
describe("ToggleButtonGroupComponent onChange Testing", () => {
const onChange = vi.fn();
it("toggle group change value and new value updated and last value no more checked", () => {
const { container } = render(<ToggleButtonGroupComponent {...props} onChange={onChange} />);
// Before change selection
const allValueToggleButton = QueryAttributeById(container, "ssh") as HTMLInputElement;
expect(allValueToggleButton.value).toEqual("ssh");
// Change selection
const withValueToggleButton = QueryAttributeById(container, "http") as HTMLInputElement;
fireEvent.click(withValueToggleButton);
expect(withValueToggleButton.value).toEqual("http");
// Old value is no more checked
expect(allValueToggleButton.value).toEqual("ssh");
});
});
What is the most efficient way to close menu on click in React functional component?
I'm trying to get <Menu /> close on clicking either <Link />or outside menu. Currently it stays open when I navigate to other component.
I use: https://github.com/negomi/react-burger-menu
MobileMenu.js
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import { elastic as Menu } from 'react-burger-menu';
import './MobileMenu.scss';
const MobileMenu = () => {
const [menuOpenState, setMenuOpenState] = useState(false)
const MyContext = React.createContext();
// const showSettings = event =>{
// event.preventDefault();
// }
return (
<div className="mobileMenu" id="outer-container">
<Menu right pageWrapId={ "page-wrap" } outerContainerId={ "outer-container"} isOpen={ false }>
<main id="page-wrap">
<MyContext.Provider value={{
isMenuOpen: menuOpenState,
toggleMenu: () => setMenuOpenState(!menuOpenState),
stateChangeHandler: (newState) => setMenuOpenState(newState.isOpen)
}}>
</MyContext.Provider>
<Link id="home "to={'/'} className="menu-item">home</Link>
<Link id="projects" to={'/projects'} className="menu-item">projects</Link>
<Link id="experiment" to={'/experiment'} className="menu-item">experiment</Link>
{/* <a onClick={ showSettings } className="menu-item--small" href="/">Settings</a> */}
</main>
</Menu>
</div>
)
}
export default MobileMenu
one way to do it is add a div element with absolute value and stretch the entire screen display on let's say z-index: 100; and your menu on z-index: 101; and open the element only with the menu and set the onClick={() =>setMenuOpenState(false)} this way it's a little more efficient
i am working on preact app and i have different components imported in a single page, i want to click on button in header and scroll to particular component.
this is my parent component
<div class={style.root}>
<Header />
<Landing />
<HowItWorks />
<BrowserCatalogue />
<ContactUs />
<Footer />
</div>
and in my header i have 3 buttons
<div class={styles.headerItems}>
<span style={styles.pointer}>Working</span>
<span style={styles.pointer}>Catalogue</span>
<span style={styles.pointer}>Contact</span>
</div>
</div>
like when i click on working my page should scroll to HowItWorks component.any help?
Let me help you friend. You should introduce refs in your parent component.
We will wrap each section in a div and give it a ref prop.
Here is sandbox for your reference: https://codesandbox.io/s/navbar-click-scroll-into-section-us8y7
Parent Component
import React from "react";
import ReactDOM from "react-dom";
import Header from "./Header";
import HowItWorks from "./HowItWorks";
import BrowserCatalogue from "./BrowserCatalogue";
import "./styles.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
selected: null
};
}
//refs
howItWorks = React.createRef();
browserCatalogue = React.createRef();
changeSelection = index => {
this.setState({
selected: index
});
};
componentDidUpdate() {
this.scrollToSection(this.state.selected);
}
scrollToSection = index => {
let refs = [this.howItWorks, this.browserCatalogue];
if (refs[index].current) {
refs[index].current.scrollIntoView({
behavior: "smooth",
block: "nearest"
});
}
};
render() {
return (
<div className="App">
<div>
<Header changeSelection={this.changeSelection} />
</div>
<div ref={this.howItWorks}>
<HowItWorks />
</div>
<div ref={this.browserCatalogue}>
<BrowserCatalogue />
</div>
</div>
);
}
}
Header
const Header = (props) => {
const { changeSelection } = props;
return (
<div style={{ background: "green" }}>
<span onClick={() => changeSelection(0)}>Working</span>{" "}
<span onClick={() => changeSelection(1)}>Catalogue</span>{" "}
<span>Contact</span>
</div>
);
}
Workflow:
Each component gets a ref, and we keep that in memory for when we
need to scroll.
Header, we defined a handler in parent called changeSelection()
and we pass it as prop. It takes an index and we use that index to
update the parent state.
Each link, "Working", "Catalogue", etc, will correspond to an index
that matches with a ref in our parent, so setting up an onClick() handler for each span will allow us to pass in that index to changeSelection()
parent state is updated, triggers componentDidUpdate(), in there
we run scrollToSection() which you guessed it takes in an index (stored in our state as "selected"). Create an array of our refs, and simply use the matching index to locate that ref and scroll to that component.