-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How can I add a class of active to the Link component? #682
Comments
Actually @elasim Gave me the answer. The answer is as follows:
Note this is throwing me an error in the console warning.js?85a7:44Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server: Any Idea on how to solve that? |
With |
I didn't know that api. that's definitely better. use history.getCurrentLocation() |
I put it like this in this Boiler plate
and is throwing an error
|
@frenzzy so this API only works in history module v 3.0? wow let me try that right now |
Try logging the path somewhere to check if it's the same with what you're expecting (e.g. '/dribbble/' instead of '/dribbble'). Probably you should use regex to match path, because this won't work for '/dribbble/subpath'. |
@arvigeus I already try that and the path is always '/' root |
With Redux, I'm currently using this hack: server.js
client.js
MyComponent.js
just sharing, hoping to find a more robust and redux-free method. |
@daiky00 In reactjs, render() not work until you change state using setState() or prop on parent component |
@elasim Yeah when I render I make sure I change the state before I console.log the element and I already knew that but thanks for the tip. I just change the whole structure of the project and use react router instead. I don't like the universal router currently in this boiler plate. React Router should be in this Boiler Plate +1 for that |
I'm having a similar issue where adding a class on the client side causes a React checksum warning since the code doesn't match between client and server. This is the message that I get in the browser:
Thanks for your help! |
@rkait good catch! It might be better idea to initialize a new |
@rkait have you tried something like this? const yourRoute = {
path: '/some-page',
action({ path }) {
return <div>Current Path: {path}</div>
}
} or const routes = {
path: '/',
async action({ path, next, render }) {
const component = await next();
if (component !== undefined) {
return render(<Layout currentPath={path}>{component}</Layout>);
}
},
children: [ /* Nested Routes Here */ ]
} |
I ended up using the solution with redux from @awesomejerry above. Would love to know if there is a better solution in the future. Thanks! |
I saw some workarounds, but why history.getCurrentLocation() doesn't return the right URL on the server side? What I should I do to get that right? (it would be nice if it's possible avoid using argument/parameter on the render components) |
@kaitlynreese @jlVidal I needed to highlight the active navigation tab - might be overkill but I solved the issue by making a component that used state to track whether the current url path was active.
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import Link from '../Link';
import s from './HeaderLink.css';
import history from '../../history';
class HeaderLink extends Component {
constructor(props) {
super(props);
this.state = {
isActive: false,
};
}
componentDidMount() {
this.onPath();
}
componentWillReceiveProps() {
this.onPath();
}
onPath() {
if (history.location.pathname.includes(this.props.to)) {
this.setState({ isActive: 'active' });
} else {
this.setState({ isActive: false });
}
}
render() {
return (
<Link
to={this.props.to}
className={cx(s.link, this.state.isActive && s.active)}
>
<span>{this.props.title}</span>
{this.state.isActive && <span className={s.activeAfterStyle} />}
</Link>
);
}
}
HeaderLink.propTypes = {
to: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
};
export default withStyles(s)(HeaderLink);
import React, { Component } from 'react';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import HeaderLink from './HeaderLink';
import s from './Navigation.css';
class Navigation extends Component {
render() {
return (
<nav className={s.root}>
<div className={s.navMenu}>
<div className={s.navPages}>
<HeaderLink title="Home" to="/" />
<HeaderLink title="About" to="/about" />
<HeaderLink title="Contact" to="/contact" />
</div>
</div>
</nav>
);
}
}
export default withStyles(s)(Navigation); |
I got here looking for an answer to this problem, and after reading this thread I think I will just go for the custom link solution provided in the docs, and styling the nested link with a container class. |
Use NavLink to specify active classname without any extra work. About |
I used application context to get the current path of the router, since History is used only on the client side, the below code works on both server and client; import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import ApplicationContext from 'ApplicationContext';
import history from '../../history';
function isLeftClickEvent(event) {
return event.button === 0;
}
function isModifiedEvent(event) {
return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
}
function handleClick(props, event) {
if (props.onClick) {
props.onClick(event);
}
if (isModifiedEvent(event) || !isLeftClickEvent(event)) {
return;
}
if (event.defaultPrevented === true) {
return;
}
event.preventDefault();
history.push(props.to);
}
const Link = React.forwardRef((props, ref) => {
const { context } = useContext(ApplicationContext);
const { activeClassName, to, children, ...attrs } = props;
const isActive = context.pathname === to;
attrs.className = isActive
? `${attrs.className} ${activeClassName}`
: attrs.className;
return (
<a ref={ref} href={to} {...attrs} onClick={e => handleClick(props, e)}>
{children}
</a>
);
});
if (__DEV__) {
Link.displayName = 'Link';
}
Link.propTypes = {
activeClassName: PropTypes.string,
to: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
onClick: PropTypes.func,
};
Link.defaultProps = {
activeClassName: 'active',
onClick: null,
};
export default Link; |
@daiky00 thank you very much for crating this issue! Unfortunately, we have close it due to inactivity. Feel free to re-open it or join our Discord channel for discussion. NOTE: The |
I am trying to do this for Example
this is how my navigation is
and this the Link Component code.
Any Ideas?
The text was updated successfully, but these errors were encountered: