Home > Enterprise >  How can I access query parameters passed via <Link> within a class component?
How can I access query parameters passed via <Link> within a class component?

Time:11-13

I am using react-router-dom V6, with several different Class components that are connected with various nested within each component. In App.js, I have defined my browser router and routes as follows:

// import omitted for simplicity

function App() {
  return (
    <BrowserRouter>
      <NAVBAR />
      <Routes>
        <Route path="/" element={ <SHOW_OPTIONS />} />
        <Route path="/view_list/:list_id" element={ <SHOW_LIST />} />
        <Route path="/authorize" element={ <AUTHORIZE_ITEM /> } />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

Inside of SHOW_OPTIONS, I have a option that brings you to /view_list/:list_id. Inside SHOW_OPTIONS, I need to take the list_id out of the parameter and then query a database for everything with that list_id, then display the list for the end user to browse.

Where I am running into issues is getting that query parameter out of the URL in my class component, since I cannot use any hooks directly from the class.

Here is what my SHOW_LIST class looks like:

export class SHOW_LIST extends Component {
    constructor(props) {
        super(props);
        // Here I want to be able to assign my query
        // param to this.state.list_id
        this.state = {
            list_id: '',
            items: '',
            items_selected: ''
        }
    }

    componentDidMount() {
        getListData(this.state.list_id) // this is == '' right now should be
            .then(res => res.json())              // what was passed
            .then(data => {
                console.log(data);
                this.setState({items: data});
            })
            .catch(err => {
                console.log(err);
            });
    }

    buildList() {
      // where the list is actually
      // built using this.state.items
      return (
        <div>I made it through!</div>
      )
    }

    render () {
        if(this.state.items != null) {
            return (
              {this.buildList()}
            );
        } else {
            return (
                <div id="loading">
                    Loading...
                </div>
            );
        }
    }
}

My link to the SHOW_LIST component looks like this:

<Link to = {{pathname: '/view_list/' list_id}}></Link>

My initial solution was to do something like what's being done here, but since I need to access the query parameters within my class component, I'm not certain this resolution will work. How to pass params into link using React router v6?

CodePudding user response:

Once you've followed the directions of the linked answer and created a custom withRouter HOC to inject the route path params you access them via the props object.

Given withRouter HOC:

const withRouter = WrappedComponent => props => {
  const params = useParams(); // <-- these are the path params
  // etc... other react-router-dom v6 hooks

  return (
    <WrappedComponent
      {...props}
      params={params}
      // etc...
    />
  );
};

And route path:

path="/view_list/:list_id"

Decorate the component and access them via this.props.params.list_id. Don't store list_id prop in state as this is actually an anti-pattern in React (storing passed props in local state).

export class SHOW_LIST extends Component {
  constructor(props) {
    super(props);
    this.state = {
      items: null,
      items_selected: ''
    }
  }

  componentDidMount() {
    getListData(this.props.params.list_id) // <-- consume from props
      .then(res => res.json())
      .then(data => {
        console.log(data);
        this.setState({items: data});
      })
      .catch(console.error);
  }

  buildList() {
    // where the list is actually
    // built using this.state.items
    return (
      <div>I made it through!</div>
    )
  }

  render () {
    if (this.state.items !== null) {
      return this.buildList();
    } else {
      return (
        <div id="loading">
          Loading...
        </div>
      );
    }
  }
}

Export the decorated SHOW_LIST:

export default withRouter(SHOW_LIST);
  • Related