7

I thought this would be easy, but still can't find an easy solution. I simply want to set the page title (and document.title) to a specified string that I choose. I know I can access useLocation and get the current route, but that doesn't work with logical human naming. For example, my route might be /new but I want the title of the page to be 'Add New Thing'. Notice that I've added a new prop for the page title that seems like a logical place to add it (then use a useEffect to pull it), but can't figure out how to access this prop.

If this isn't the correct way, how would you do this? Should I instead setup a dictionary/lookup for the current url(useLocation) and assign a human page title?

Main goal: If someone DIRECTLY hits a URL '/new' how would you set the title?

My current structure is from a base create react app.

In my index.js

ReactDOM.render(
    <React.StrictMode>
      <Router>
        <App />
      </Router>
    </React.StrictMode>,
    document.getElementById('root')
);

app.js

<div className="quiz-app-row">
        <SideBarNav />
        <div className='quiz-app-col'>
          <h1>{TITLE HEREEEEE}</h1>
          <Switch>
            <Route exact component={Home} path="/" title='home' />
            <Route exact component={Example} path="/manage" title='example' />
            <Route exact component={CreateQuiz} path="/new" title='New Quiz' />
          </Switch>
        </div>
      </div>
2
  • Didn't you want to replace the <h1>TITLE HEREEEEE</h1> with dynamic title? Commented Jan 13, 2021 at 17:49
  • @TaghiKhavari yes, but since I had no way yet of accessing the title prop of <Route> I didn't even show it. I'll edit it just in case others are confused. Commented Jan 13, 2021 at 20:54

4 Answers 4

7

Thanks all for the responses, but I feel most of them seem to be overkill for what I'm trying to accomplish, and no extra package needed. Instead, I just created a lookup collection and assigned the title that way. I will only have ~7 links total, so this seems manageable.

const [pageTitle, setPageTitle] = useState('Home');

  const titleMap = [
    {path: '/', title:'Home'},
    {path: '/manage', title:'Manage'},
    {path: '/new', title:'New Quiz'}
  ]

  let curLoc = useLocation();
  useEffect(() => {
    const curTitle = titleMap.find(item => item.path === curLoc.pathname)
    if(curTitle && curTitle.title){
      setPageTitle(curTitle.title)
      document.title = curTitle.title
    }
  }, [curLoc])
Sign up to request clarification or add additional context in comments.

1 Comment

Just a review comment, your solution which works fine however it is using imperative approach (ie. updating the document manually) whereas using react-helmet is the declarative approach
3

Use react-helmet to set the title dynamically

Install it by using

npm install --save react-helmet

Now when you installed react-helmet, you can use it by simply putting this fragment anywhere

import {Helmet} from "react-helmet";
...
<Helmet>
    <title>My title</title>
</Helmet>

Example Approach

You can create your own route variant in a different file

import React from "react";
import {Helmet} from "react-helmet";

const RouteWithTitle = ({ component: Component, title, ...rest}) => (
   <Route {...rest} render={(props)=> (
       <Helmet>
           <title>{title}</title>
       </Helmet>
       <Component {...routeProps} />
   )} />
)

I hope this wll help you.

Comments

2

I think the best way to do what you're trying to accomplish based on your App Component is to use a Context for your title like this:

first create Title Context like this:

const TitleContext = React.createContext();
const useTitle = () => React.useContext(TitleContext);

const TitleProvider = ({ children }) => {
  const [title, setTitle] = useState("THIS IS DEFAULT TITLE");

  return (
    <TitleContext.Provider value={{ title, setTitle }}>
      {children}
    </TitleContext.Provider>
  );
};

Then you need to change your App Component a bit

const App = () => {
  const { title } = useTitle();

  return (
    <div className="quiz-app-row">
      <SideBarNav />
      <div className="quiz-app-col">
        <h1>{title}</h1>
        <Switch>
          <Route exact component={Home} path="/" title="home" />
          <Route exact component={Example} path="/manage" title="example" />
          <Route exact component={CreateQuiz} path="/new" title="New Quiz" />
        </Switch>
      </div>
    </div>
  );
};

also wrap your App Component in TitleProvider like this:

ReactDOM.render(
  <React.StrictMode>
    <TitleProvider>
      <Router>
        <App />
      </Router>
    </TitleProvider>
  </React.StrictMode>,
  document.getElementById("root")
);

and finally you can set the title in your components like this

const Home = () => {
  const { setTitle } = useTitle();

  React.useEffect(() => {
    setTitle('This is human readable title for Home Component')
  }, [])

  return <div>I'm Home Component</div>;
};

Comments

1

use document.title = "Add New Thing"; on your CreateQuiz component. im not sure if its the best way. But it works for me

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.