React Router and syncfusion grid : You should not use <Link> outside a <Router>

Hello i tried to use react router with syncfusion but i got this error : You should not use <Link> outside a <Router>

Please take a look at the sandbox here : https://stackblitz.com/edit/react-w5c9c9-jujuby?file=index.js

The error is due to this line : template={rowData => <Link to={"/order/" + rowData.OrderID}> go to ID </Link> }

Regards,

5 Replies 1 reply marked as answer

RR Rajapandi Ravi Syncfusion Team August 28, 2020 11:39 AM UTC

Hi Jonathan, 

Greetings from syncfusion support 

Query# You should not use <Link> outside a <Router> 
 
We have analyzed your shared stackblitz sample and we could see that error “You should not use <Link> outside a <Router>”. From validating your code example we could see that In OrderID column you are using a template property. In that template property you are define a <Link> tag without a <Router>. To overcome your reported problem, you have to define the <Link> inside the <Router> tag. Please refer the below code example and sample for more information. 
 

export class Sample extends SampleBase { 
  render() { 
    return ( 

        <div className="control-pane"> 
          <div className="control-section"> 
            <GridComponent 
              dataSource={orderDetails} 
              ref={grid => (this.gridInstance = grid)} 
              allowPaging={true} 
              allowExcelExport={true} 
              allowPdfExport={true} 
              load={this.load} 
            > 
              <ColumnsDirective> 
                <ColumnDirective 
                  field="OrderID" 
                  headerText="Order ID" 
                  width="120" 
                  textAlign="Right" 
                  template={rowData =><Router> <Link to={"/order/" + rowData.OrderID}> go to ID </Link></Router>//define the <Router> tag here 
                ></ColumnDirective> 
              </ColumnsDirective> 
              <Inject 
                services={[Page, Toolbar, ExcelExport, PdfExport, Group]} 
              /> 
            </GridComponent> 
          </div> 
          </div> 
    ); 
  } 



Regards, 
Rajapandi R 



JP Jonathan Payet August 31, 2020 06:05 AM UTC

Hello,

Thanks for your reply but it's not supposed to work like that. The router provider must be declared once and higher in the tree (like I did). Not every time I need to use a Link component. And please check your example, it didn't work correctly, even with "Router" it didn't go to the correct page.


RR Rajapandi Ravi Syncfusion Team September 2, 2020 02:16 PM UTC

Hi Jonathan, 

Thanks for the update 

Based on your requirement we have created a sample  “Grid with React Router Dom link inside the Grid coulmn template”.   
   
We have imported Router, Switch from “react-router-dom” initialized Routing Component.  Please find the code example.  

  
[App.tsx]  
  
import * as React from "react";  
import * as ReactDOM from 'react-dom';  
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";  
import Grid from './Grid';  
import Home from './Home';  
import Nav from './navpage';  
  
export default class App extends React.Component<{}, {}> {  
    render() {  
        return (  
            <Router>  
                <div>  
                    <ul>  
                        <li><Link to={'/'}>Home</Link></li>  
                        <li><Link to={'/Grid'}>Grid</Link></li>  
  
                    </ul>  
                    <hr />  
                    <Switch>  
                        <Route exact path='/' component={Home}></Route>  
                        <Route exact path='/Grid' component={Grid}></Route>  
                        <Route exact path='/navpage' component={Nav}></Route>  
                    </Switch>  
                </div>  
            </Router>  
  
        );  
    }  
}  
ReactDOM.render(<App />, document.getElementById('grid'));  
  
  
  
We have created a link element inside the Grid cell by using ‘queryCellInfo’ event. When click the link element we navigate to ‘navpage.tsx’. please find the code example .  
   
  
[Grid.tsx]  
  
import * as React from 'react';  
import * as ReactDOM from 'react-dom';  
  
import {  
    GridComponent, Sort, ColumnsDirective, ColumnDirective,  
    Inject, Page  
from '@syncfusion/ej2-react-grids';  
import './App.css';  
import { orderDetails } from './data';  
  
  
export default class Grid extends React.Component<{}, {}> {  
  
    public gridObj: GridComponent | null;  
  
    public load(args: any): void {  
  
    }  
  
    public renderAnchor(args: any): void {  
        if (args.column.field == "CustomerID") {  
            //template create  
            ReactDOM.render(<a className='acrele' onClick={this.onChange.bind(this)} rel='nofollow' rel='nofollow' href='#'>{args.cell.innerText}</a>, args.cell)  
        }  
    }  
    public onChange(args: any) {  
        //call event when click the link  
        if (args.target.classList.contains('acrele')) {  
            let rowData: Object | null = this.gridObj ? this.state = { rData: this.gridObj.getRowInfo(args.target.parentElement).rowData } : null;  
            this.setState({ rData: rowData });   
            (this.props as any).history.push('/navpage') //navigate to new page  
        }  
  
    }  
    render() {  
        return (  
            <div>  
                <GridComponent dataSource={orderDetails} queryCellInfo={this.renderAnchor.bind(this)} ref={grid => this.gridObj = grid} allowPaging={true} load={this.load} allowSorting={true}>  
                    <ColumnsDirective>  
                        <ColumnDirective field='OrderID' headerText='ID' width='120' ></ColumnDirective>  
                        <ColumnDirective field='CustomerID' headerText='CustomerID' width='160'></ColumnDirective>  
                        <ColumnDirective field='Freight' headerText='Freight' width='160'></ColumnDirective>  
                    </ColumnsDirective>  
                    <Inject services={[Page, Sort]} />  
                </GridComponent>  
            </div>  
        );  
    }  
}  
ReactDOM.render(<Grid />, document.getElementById('grid'));  
 
  

Regards, 
Rajapandi R 


Marked as answer

JP Jonathan Payet September 3, 2020 05:59 AM UTC

Wow ... Thank you for your example but no thank you. If I want to do it with a history.push I can do it without doing all of that DOM manipulation already ... like so: https://stackblitz.com/edit/react-w5c9c9-fbbj5v?file=index.js , what i really want is using directly Link component in template, like in my first sample. 

This is not a problem specific to React Router, we also use Material UI / React redux and many others .. And each time a component must be passed in the template we must each time pass the providers back to it.. While normally once you declare at the root of the application it is no longer necessary to do so. 

I'm using the Link component as an example, because it's the easiest to show. But the problem is there, it is not at all react fliendly to proceed as shown in your examples.


RS Rajapandiyan Settu Syncfusion Team September 8, 2020 02:08 PM UTC

Hi Jonathan, 

Thanks for your update. 
 
Currently, we don’t have the support to access react hooks properties inside the template. We have already logged the bug task for this requirement. We assure you that we will fix this issue in our Volume 3, 2020 release scheduled at the end of September as promised and you can track this issue using the below feedback.  
  
You can now track the current status of your request, review the proposed resolution timeline, and contact us for any further inquiries through this link. 


Regards, 
Rajapandiyan S 


Loader.
Up arrow icon