Programmerzzz
Programmerzzz

Reputation: 1287

Error: Invariant failed: You should not use <Link> outside a <Router> ,No Navigation occurs

I am trying to use Link Component to enable client side rendering of my app. Below is my component.

/**@jsx jsx */
import { css, jsx } from '@emotion/core';
import { fontFamily, fontSize, gray1, gray2, gray5 } from './../Styles';
import UserIcon from './UserIcon';
import { ChangeEvent } from 'react';
import { Link, BrowserRouter } from 'react-router-dom';

export const Header = () => {
    const handleSearchInputChange = (e: ChangeEvent<HTMLInputElement>) => {
        console.log(e.currentTarget.value);
    };
    return (
        <div
            css={css`
                position: fixed;
                box-sizing: border-box;
                top: 0;
                width: 100%;
                display: flex;
                align-items: center;
                justify-content: space-between;
                padding: 10px 20px;
                background-color: #fff;
                border-bottom: 1px solid ${gray5};
                box-shadow: 0 3px 7px 0 rgba(110, 112, 114, 0.21);
            `}
        >
            <Link
                to="./"
                css={css`
                    font-size: 24px;
                    font-weight: bold;
                    color: ${gray1};
                    text-decoration: none;
                `}
            >
                Q & A
            </Link>
            <input
                type="text"
                placeholder="Search..."
                css={css`
                    box-sizing: border-box;
                    font-family: ${fontFamily};
                    font-size: ${fontSize};
                    padding: 8px 10px;
                    border: 1px solid ${gray5};
                    border-radius: 3px;
                    color: ${gray2};
                    background-color: white;
                    width: 200px;
                    height: 30px;
                    :focus {
                        outline-color: ${gray5};
                    }
                `}
                onChange={handleSearchInputChange}
            />
            <Link
                to="./signin"
                css={css`
                    font-family: ${fontFamily};
                    font-size: ${fontSize};
                    padding: 5px 10px;
                    background-color: transparent;
                    color: ${gray2};
                    text-decoration: none;
                    cursor: pointer;
                    span {
                        margin-left: 10px;
                    }
                    :focus {
                        outline-color: ${gray5};
                    }
                `}
            >
                <UserIcon />
                <span>Sign In</span>
            </Link>
        </div>
    );
};

I am using BrowserRouter in my App.tsx as below

const App = () => (
    <div
        className="App"
        css={css`
            font-family: ${fontFamily};
            font-size: ${fontSize};
            color: ${gray2};
        `}
    >
        <Header />
        <BrowserRouter>
            <Switch>
                <Redirect from="/home" to="/" />
                <Route exact path="/" component={HomePage} />
                <Route exact path="/search" component={SearchPage} />
                <Route exact path="/ask" component={AskPage} />
                <Route exact path="/signin" component={SignInPage} />
                <Route component={NotFoundPage} />
            </Switch>
        </BrowserRouter>
    </div>
);
export default App;

Now when I run my app, I get the Error as

Error: Invariant failed: You should not use <Link> outside a <Router>
▶ 25 stack frames were collapsed.

My App runs when I use BrowserRouter in my Header.tsx around the Link component, but when I click my links, just the URL changes and app stays at home page. Not sure what am I missing here.

Upvotes: 0

Views: 46

Answers (1)

Shubham Khatri
Shubham Khatri

Reputation: 281774

Your Header component which uses Link is rendered outside of the BrowserRouter component which is why it is throwing the error. You can render it as a child of BrowserRouter and as a default Route so that it receives the router props and is able to use Link correctly

const App = () => (
    <div
        className="App"
        css={css`
            font-family: ${fontFamily};
            font-size: ${fontSize};
            color: ${gray2};
        `}
    >

        <BrowserRouter>
            <Route component={Header} />
            <Switch>
                <Redirect from="/home" to="/" />
                <Route exact path="/" component={HomePage} />
                <Route exact path="/search" component={SearchPage} />
                <Route exact path="/ask" component={AskPage} />
                <Route exact path="/signin" component={SignInPage} />
                <Route component={NotFoundPage} />
            </Switch>
        </BrowserRouter>
    </div>
);
export default App;

Upvotes: 2

Related Questions