How to ignore Material UI theme styling for component? - reactjs

My button component (that is also a material UI component) already has the style I want, but when I surround it with the Link component, which is a react-dom-router component, it overrides the style of my button.
How to ignore the default style of Link?
<AppBar>
<Toolbar>
<Link to="/some-link">
<Button>
My Button
</Button>
</Link>
</Toolbar>
</AppBar>

Nesting a Link (<a>) inside a Button (<button>), and viceversa, is not valid HTML. I would recommend you either remove the Button or you use react-router and add props.history.push("/some-link") to your Button onClick handler. Like this:
<Button onClick={() => history.push("/some-link")}>My Button</Button>
Take a look at this sandbox I made. Let me know if it helps.

Instead of nesting a button inside a Link (which is weird because they are both clickable elements) just use the Button with an onClick handler where you can manually trigger the route change.
See also React-router: How to manually invoke Link?

Here's the example given on the material ui site. You probably don't need the router part though.
https://material-ui.com/components/buttons/#ButtonRouter.js
import React from 'react';
import { MemoryRouter as Router } from 'react-router';
import { Link } from 'react-router-dom';
import Button from '#material-ui/core/Button';
// The usage of React.forwardRef will no longer be required for react-router-dom v6.
// see https://github.com/ReactTraining/react-router/issues/6056
const AdapterLink = React.forwardRef((props, ref) => <Link innerRef={ref} {...props} />);
const CollisionLink = React.forwardRef((props, ref) => (
<Link innerRef={ref} to="/getting-started/installation/" {...props} />
));
export default function ButtonRouter() {
return (
<Router>
<Button color="primary" component={AdapterLink} to="/">
Simple case
</Button>
<Button component={CollisionLink}>Avoids props collision</Button>
</Router>
);
}

Related

how to redirect to a specific tab in another page using react

<button onClick={()=>history.push("/page")}> Redirect </button>
code for /page component:
const[toggle,setToggle] = useState<boolean>(true);
return(
<div>{toggle? <Tab1Container /> : <Tab2Container />} </div>
)
there are 2 different tabs on /page, lets say tab1 and tab2, by default when you loading /page, it shows tab1 component. How can I redirect to tab2 component when I click on the button?
You can use Link and useLocation from react-router-dom to achieve the result you want. It can be used as:
You can use the following code on the page where the button is present.
import { Link } from 'react-router-dom'
<Link
to={{
pathname: '/page',
state: {
toggleValue: false
}
}}
>
<button onClick={()=>history.push("/page")}> Redirect </button>
</Link>
On the page component
import {useLocation } from 'react-router-dom'
const location = useLocation()
const { toggleValue } = location?.state ?? {}
const[toggle,setToggle] = useState<boolean>(toggleValue);
return(
<div>{toggle? <Tab1Container /> : <Tab2Container />} </div>
)
Also, you can set toogle value on useEffect hook when page load and to change the tab on page use setToggle on handle function
Just uplift the useState of the toggle Button or use context api or state management libraries..
From your parent component..
Pass SetToggle as props to the button component &
Pass toggle as props to the Page Component
<button onClick={()=>setToggle(!toggle)}> Redirect </button>
For your reference,
https://reactjs.org/docs/lifting-state-up.html

what differences between Link in react-router and `window.history.pushState()`?

in my code when i click button, component Aaaaa is not re-rendered, but when i tap on link, component Aaaaa is re-rendered. i can't find cause of it?
function App() {
return (
<>
<button onClick={() => window.history.pushState('','','/about')}>About</button>
<Link to='/about'>to About</Link>
<Aaaaaa/>
</>
);
}
and:
Aaaaaa(){
const location = useLocation()
return <div>About </div>
}
The proper way is to use <Link to='/about'>to About</Link> when trying to navigate manually (by clicking a button) and window.history.pushState('','','/about') when trying to navigate automatically (like after completing an API call).
cause window.history.pushState is not using the react router
so you can use link to navigate between the pages.
but if you have limits and you want it to be a buttn and still navigate using react router, you can use history from react-router-dom
import { withRouter } from 'react-router-dom'
// some other codes
const { history } = props;
// some other codes
<button onClick={() => history.push('/about')}>About</button>
// some other codes
export default withRouter(MyComponent)
or you can use 'useHistory' hook if you're using react-router v5.
import { useHistory } from 'react-router-dom'
// some other codes
const history = useHistory();
// some other codes
<button onClick={() => history.push('/about')}>About</button>
// some other codes
export default MyComponent
I found that window.history.pushState('','','/about') does not work as expected. The router does not update what route to display.
If you cant use a button and need to control the location programatically, but use class components wrap it in a function component like this:
... other routes
<Route exact path="/register" component={()=>{
const history = useHistory();
return <RegisterPage onRegister={async (account) => {
this.setState({ account });
history.push('/'); // sends user automatically to main page
}} />
}} />
...
window.history.pushState method doesn't trigger any browser event, which in turn doesn't notify react router about the update you made to the history object
React router custom Link component is most likely going to use a custom event or the observer design pattern to be able to notify and respond to changes in the window history object

How to access name of a button type mui ListItem in react

I have create a material-ui list, in which each ListItem is a button, but when I try to access the name prop of the button it gives undefined.
import React from 'react';
import LoginFront from './login/loginFront';
import {BrowserRouter, Route} from 'react-router-dom';
import {List, ListItem, ListItemText} from '#material-ui/core';
class App extends React.Component {
render(){
return(
<List component='nav'>
<ListItem button name='bName' onClick={event => console.log(event.target.name)} />
<ListItemText primary='item1' />
</List>
)
}
}
export default App;
console.log(event.target.name) gives undefined
onClick={event => console.log(event.target.getAttribute('name'))}
Use the getAttribute method to get the value of name
The html you see on the page is just the rendered representation of the DOM. The properties of nodes on the DOM tree don't match up with the attributes on the html element.
When creating the standard they wouldn't have wanted the interface for the DOM element be the same as the attribute because you might add an attribute that conflicts with an existing property or method however this is just conjecture.
EDIT
onClick={event => console.log(event.currentTarget.getAttribute('name'))}
See here for the difference between target and currentTarget.
The thing is when you define onClick on the topMost parent, you need to use e.currentTarget.id instead of e.target.id since e.target will give you the element on which you clicked rather then the parent on which onClick listener is defined
Material-ui does not have a native way to do it. A simple way to bypass it is to not use name at all and pass your parameter in a preset function.
class App extends React.Component {
clickHandler = name => ev => {
console.log(name)
}
render() {
return (
<List component='nav'>
<ListItem button onClick={this.clickHandler('bName')} />
<ListItemText primary='item1' />
</List>
)
}
}
export default App;

react-router connected to redux : works with links but only the URL change when dispatching push

I'm trying to programmatically push an URL to navigate with react-router, redux, and connected-react-router
When clicking on a <Link /> button, it's working great, the URL is changing and the route too.
But when using a dispatch(push(url)), the URL only change and the content is not updated
I've made a minimal example here.
Any help would be really grateful,
Thanks
A lot of anti-pattern code, poor application structured, and mixing of packages is holding your application back.
I rewrote it entirely, here's what I've done:
Reconfigured your application folder's structure to be standard.
Don't mix Router (BrowserRouter) with ConnectedRouter.
Don't place all of your components within the App.js file.
Since the Header is always mounted, you don't need redux, instead you can just use withRouter (it exposes route props to the component).
Your rootReducer is missing a reducer, so I added a dummyReducer that just returns state.
Stick to Link or this.props.history when navigating. For this example, there's no need to use both. Also, you don't need to use ConnectedRouter's push function, because the history is passed as a prop when using withRouter.
Side note: If you want the Header to be a "router" where all route changes pass through here, then you'll need to create an action and a reducer that passes a string and stores it to the redux's store. The Header is then connected to the redux store and updates the route when this string has changed.
Working example: https://codesandbox.io/s/526p7kjqq4
components/Header.js
import React, { PureComponent, Fragment } from "react";
import { withRouter } from "react-router-dom";
class Header extends PureComponent {
goTo = route => {
this.props.history.push(route);
};
render = () => (
<Fragment>
<ul>
<li>
<button onClick={() => this.goTo("/")}> Announcements </button>
</li>
<li>
<button onClick={() => this.goTo("/shopping")}> Shopping </button>
</li>
</ul>
<div>
<button onClick={() => this.goTo("/shopping")}>
Click here to go shopping ! (if you can...)
</button>
</div>
</Fragment>
);
}
export default withRouter(Header);
routes/index.js
import React from "react";
import { Switch, Route } from "react-router-dom";
import Announcements from "../components/annoucements";
import Shopping from "../components/shopping";
export default () => (
<div style={{ padding: "150px" }}>
<Switch>
<Route exact path="/" component={Announcements} />
<Route path="/shopping" component={Shopping} />
</Switch>
</div>
);
components/App.js
import React, { Fragment } from "react";
import Routes from "../routes";
import Header from "./Header";
export default () => (
<Fragment>
<Header />
<Routes />
</Fragment>
);
Here is what you're trying to accomplish: https://codesandbox.io/s/8nmp95y8r2
However, I DO NOT recommend this as it's a bit unnecessary, when history is either already passed as a prop from the Route or can be exposed when using withRouter. According to the Redux docs, it's not recommended either. And instead to either use Link or pass the history prop to the redux action creator instead of programmatic navigation through redux state.
containers/Header.js
import React, { PureComponent, Fragment } from "react";
import { connect } from "react-redux";
import { push } from "connected-react-router";
class Header extends PureComponent {
goTo = route => this.props.push(route); // this is equivalent to this.props.dispatch(push(route)) -- I'm just appending dispatch to the push function in the connect function below
render = () => (
<Fragment>
<ul>
<li>
<button onClick={() => this.goTo("/")}> Announcements </button>
</li>
<li>
<button onClick={() => this.goTo("/shopping")}> Shopping </button>
</li>
</ul>
<div>
<button onClick={() => this.goTo("/shopping")}>
Click here to go shopping ! (if you can...)
</button>
</div>
</Fragment>
);
}
export default connect(
null,
{ push }
)(Header);
After reading the complete thread react-router-redux's push() not rendering new route, I came across this solution you need to use Router with passing down history as prop down to your app and don't use create from multiple files just import it from a common file.
Here is the working codesandbox: push rendering the new route

Passing a NavLink to a Material UI component via the containerElement prop gives “Failed prop type” warning

<RaisedButton containerElement={NavLink} to="/somewhere">
Somewhere
</RaisedButton>
Produces the following warning:
Warning: Failed prop type: Invalid prop `containerElement` supplied to `RaisedButton`.
in RaisedButton (at App.js:11)
in App (at index.js:23)
in Provider (at index.js:22)
in MuiThemeProvider (at index.js:21)
but the Navlink properly renders and redirects to /somewhere on click. If this is a deprecated prop that still works then I haven't been able to find what the new prop is called... Please advise. If nothing else I'd like to hide the warning (how?).
As of Material UI 1.0 the prop is called component:
import { Link } from 'react-router-dom'
import Button from 'material-ui/Button';
<Button component={Link} to="/open-collective">
Link
</Button>
More about Buttons.
Update:
From Material UI v4 you may need to use forwardRef and wrap Link into a div:
const LinkRef = React.forwardRef((props, ref) => <div ref={ref}><Link {...props} /></div>)
<Button component={LinkRef} to="/open-collective">
Link
</Button>
More here.
I think you need to give it the markup for the containerElement, something like this (rather than just the name of the element)
containerElement={<NavLink to="/home" />}
Give that a try and see if it works
The easiest solution is to put IconButton inside the Navlink, so whenever you click on the Iconbutton the NavLink is automatically clicked.
Here is a sample of the code:
<NavLink to="/" style={{ textDecoration: "none" }}>
<IconButton>
<Typography>Home</Typography>
</IconButton>
</NavLink>

Resources