Big React component with conditional rendering or smaller separate components? - javascript

I have a specific question about coding practices for React.js.
I have two pages in my React application that render UI cards based on data returned from the backend. They are almost identical, except one has a UI for filter options and another has a search bar.
What would be the better way of structuring these two different pages and why?
----------------
OPTION A (one big component with conditional rendering)
App.jsx
<Router>
<Routes>
<Route path="/page1" element={<Page showFilter=true showSearchBar=false />} />
<Route path="/page2" element={<Page showFilter=false showSearchBar=true />} />
</Routes>
</Router>
Page.jsx
function Page(props) {
return (
<>
<Header />
{props.showSearchBar && (<SearchBar />)}
{props.showFilter && (<Filter />)}
<ItemsList />
<Footer />
</>
)
}
----------------
OPTION B (two separate components with sub-component reuse)
App.jsx
<Router>
<Routes>
<Route path="/page1" element={<Page1 />} />
<Route path="/page2" element={<Page2 />} />
</Routes>
</Router>
Page1.jsx
function Page1(props) {
return (
<>
<Header />
<Filter />
<ItemsList />
<Footer />
</>
)
}
Page2.jsx
function Page2(props) {
return (
<>
<Header />
<SearchBar />
<ItemsList />
<Footer />
</>
)
}
----------------
Of course the above list of options isn't exhaustive. If there are any other ways to solve this that might be more suitable for my task, I'd be happy to hear it.
Thanks!

Option C React Composition
App.jsx
<Router>
<Routes>
<Route path="/page1" element={<Page><Filter /></Page>} />
<Route path="/page2" element={<Page><SearchBar /></Page>} />
</Routes>
</Router>
Page.jsx
function Page(props) {
return (
<>
<Header />
{props.children}
<ItemsList />
<Footer />
</>
)
}

I think option A seems fine also, at least until the UI start to differ significantly then you might have to go for option B.

Related

Dynamic React path Routing not matching url but matches on reload

.I am trying to move to a url using dynamic routing and using the React Link tag. The problem is that it changes the url but does not re-render the ui. When I use an anchor tag or when the page is refreshed it renders. I have been trying to detect the problem but I am currently stuck. I implemented somethings similar furhter below and its working fine.
Here is a snippet of my App.js
// Front end pages
if (isFrontEndPage()) {
return (
<Layout className="app-container">
<AppHeader />
<Layout>
<AppSidebar />
<Content className="app-content" breakpoint="lg">
<div className="container" style={{ minHeight: '100vh', padding: '10px' }} >
<Switch>
<Route path="/" exact component={Home} />
<Route path="/pricing" exact component={Pricing} />
<Route path="/features" exact component={Features} />
<Route path="/help/search/result.html" exact component={Post} />
<Route path="/help" exact render={(props) => <Redirect to="/p/help/invoices/index.html" /> } />
// I have a problem with this
<Route path="/p/:postType/:postCategoryUrlTitle/:postUrlTitle.html" component={Post} />
// I also have a problem with this
<Route path="/:postUrlTitle" component={Post} />
<Route component={NotFound} />
</Switch>
</div>
</Content>
</Layout>
<AppFooter />
</Layout>
)
}
return (
<Layout className="app-container">
<AppHeader />
<Layout>
<AppSidebar />
<Content className="app-content" breakpoint="lg">
<div className="container" style={{ minHeight: '100vh', padding: '10px' }} >
<Switch>
// The below similar links actually render accurately with dynamic routing
<PrivateRoute path="/posts/info-posts/new" component={InfoPost} />
<PrivateRoute path="/posts/info-posts/info-post/:infoPostId" component={InfoPost} />
<PrivateRoute path="/posts/info-posts" component={InfoPosts} />
<**************** OTHER PATHS ***********************>
<PrivateRoute component={NotFound} />
</Switch>
</div>
</Content>
</Layout>
<AppFooter />
</Layout>
);
}
export default App;
Below is a snippet of my Index.js
............
ReactDOM.render(
<BrowserRouter>
<AuthProvider>
<App />
</AuthProvider>
</BrowserRouter>,
document.getElementById('root')
);
When using React's Link component, the page doesn't refresh, it only switches the component/view, that is the way Link works. If you use anchor tag the page refreshes. Not sure what exactly is going on in your app, but from what I can see, I noticed that you are linking same component for more routes, maybe that is why your UI doesn't change
Finally solved the problem. Since I was already in the component that I wanted to route to, all I needed to do was to use React hook 'useRouteMatch' to actually render the component again using 'useEffect' when a change in params property of 'useRouteMatch' is detected.
...
const {postType, postCategoryUrlTitle, postUrlTitle } = useRouteMatch().params;
...
useEffect(() => {
// Now do stuff with the params
}, [postType, postCategoryUrlTitle, postUrlTitle]);

React nested routing problem (cannot displayed the child component)

I am new to react development. And I want to implement the routing mechanism in my page.
For example, there's component contains routes with the <Home /> and <Login /> component.
function App() {
return (
<div className="App">
<Switch>
<Route exact path="/home">
<Home />
</Route>
<Route path="/login">
<Login />
</Route>
</Switch>
</div>
);
}
The <Home /> component contains a <Navbar /> and a <Switch /> with two <Route />:
Home.js
function Home() {
return (
<div>
<Navbar />
<div>
<Switch>
<Route exact path={`/home`}>
<Menu />
</Route>
<Route path={`/home/temperature`}>
<div>temperature</div>
</Route>
</Switch>
</div>
</div>
)
}
However, I defined the <Link /> in the <Menu /> component as below:
function Menu() {
return (
<div>
<li>
<Link to={`/home/temperature`}>temperature child page</Link>
</li>
</div>
)
}
Originally, the page would displayed the <Home /> component with <Menu /> and <div> temperature </div>
I expected that when I clicked the link (<Link to={/home/temperature}>temperature child page</Link>) then it would replace the <Menu /> component with the only the <div>temperature</div> (Dispalyed the <Navbar/> and <div>temperature</div>, but it could not display anything.
How should I correct it?
Solution:
I finally figure out why I cannot get child component in my js script.
Firstly, I need to wrap the <Switch> with <Router> in <App> component.
Then, by reference this , I realized that I should not specify the exact in <Route path="/home"> to make sure that the nested route can work as well.
function App() {
return (
<div className="App">
<Router>
<div>
<Switch>
<Route path="/home">
<Home />
</Route>
<Route path="/login">
<Login />
</Route>
</Switch>
</div>
</Router>
</div>
);
}
simple routing
<Router>
<Switch>
<Route path={"/home"} exact component={Home} />
</Switch>
</Router>
nested routing
<Router>
<Switch>
<Route path={"/home"} exact component={Home}
<Rout path={"/temperature"} exact component={Temperature} />
</Route>
</Switch>
</Router>
`

React router rendering wrong page

i am developing an web app and I am new to react router. Evrything was going great until I found myself in need to render a whole new page, with new navbar and all.
that's my app.js
class App extends Component {
render() {
return (
<BrowserRouter>
<div className='App'>
<Layout>
<Header />
<NavigationB />
<Search />
<Switch> {/* to swtich to the desired path. Nest all route here */}
<Route path='/' component={Home} exact />
<Route path='/login' component={Login} />
<Route path='/register-choice' component={RegisterButton} />
<Route path='/register-patient' component={RegisterPatient} />
<Route path='/register-professional' component={RegisterProf} />
<Route path='/profesional-dashboard' component={ProfessionalDashboard} />
</Switch>
</Layout>
<Footer />
</div>
</BrowserRouter>
);
}
}
So, I wanted to go to /professional-dashboard but without rendenring all the components above such and Header, Search, etc.
I tried to go to my index.js file and set it up like this
ReactDOM.render(
<BrowserRouter>
<Switch> {/* to swtich to the desired path. Nest all route here */}
<Route path='/' component={App} exact />
<Route path='/professional-dashboard' component=
{ProfessionalDashboard} />
</Switch>
</BrowserRouter>,
document.getElementById('root'));
The idea was, in my form whenever I press register, it should send me to the dashboard of the professional.
At the end of my Register.js file you would find
const WrappedRegistrationForm = Form.create()(RegisterProf);
ReactDOM.render(
<BrowserRouter>
<div>
<WrappedRegistrationForm />
</div>
</BrowserRouter>
, document.getElementById('root'));
export default WrappedRegistrationForm;
I am using Ant Design, so the form renders WrappedRegistrationForm. At first it was not working then I wrapped it around BrowserRouter, I don't get the error anymore, but now when I press the register button, it takes me to /professional-dashboard but it loads app.js and not ProfessionalDashboard.js
Funny thing is, if I refresh the page, it loads ProfessionalDashboard.js normally.
Hope I'm explaining myself well.
Glad if you can help me!!
Hi could try something like this rendering the top one first if its a match if not it will go on to render the rest of the app :) hope this is clear
class App extends Component {
render() {
return (
<BrowserRouter>
<Switch>
<Route exact path='/profesional-dashboard' component={ProfessionalDashboard} />
<StandarRoute path='/' component={MainPage} />
<Switch />
</BrowserRouter>
);
}
}
class MainPage extends Component {
render(){
return(
<div className='App'>
<Layout>
<Header />
<NavigationB />
<Search />
<Switch> {
<Route path='/' component={Home} exact />
<Route path='/login' component={Login} />
<Route path='/register-choice' component={RegisterButton} />
<Route path='/register-patient' component={RegisterPatient} />
<Route path='/register-professional' component={RegisterProf} />
</Switch>
</Layout>
<Footer />
</div>
)
}
}
Try including "exact" before component in your Route, or including "exact" before the 'To' in your Link
Try,
<Route exact path="/register" render={() => ( <Redirect to="/dashboard"/>)
Why do you render two times with reactDOM by the way? That might be what’s causing the issue too. Just exporting it and putting it in route component should suffice.

Conditional loading component based on ReactRouter path

I used a React-Router, coded this
<Router>
<div className="app">
<div className="wrapper">
<AppHeaderMain />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/list/" component={List} />
<Route path="/about/" component={About} />
<Route component={NotFound} />
</Switch>
<div className="menu">
<ul>
<li><NavLink exact to="/">List</NavLink></li>
<li><NavLink to="/about/">About</NavLink></li>
</ul>
</div>
</div>
</div>
</Router>
and I have a question, is it possible to load another component based on Rout path, for example:
path="/" - load <AppHeaderMain />
path="/list/" - load <AppHeaderSubpage />
I know I could insert a AppHeader component into each single component but I would like to don't repeat some additional code which would be required to make that.
I mean something like conditional including (loading) component.
Is it a good practice? Maybe I must to do exactly how I wrote: include in each single component?
I think it is a matter of composition. Why not create a factory function. For example:
function routeHandlerWithAppHeader(Component) {
return (props) => (
<div>
<AppHeaderMain />
<Component {...props}/>
</div>;
);
}
And then use:
<Route exact path="/" component={routeHandlerWithAppHeader(Home)} />

Render multiple components in React Router

I'm used to application layouts with multiple yield areas, i.e. for content area and for top bar title. I'd like to achieve something similar in React Router. For example:
<Router>
<Route path="/" component = { AppLayout }>
<Route path="list"
component = { ListView }
topBarComponent = { ListTopBar }/>
</Route>
</Router>
AppLayout:
<div className="appLayout box">
<div className="appLayout topBar">
{ -- display ListTopBar here -- }
</div>
<div className="appLayout content">
{ -- display ListView here -- }
</div>
</div>
Both child components should receive the same props.
How can I approach this?
To passe multiple component you can do like this :
<Route path="groups" components={{main: Groups, sidebar: GroupsSidebar}} />
<Route path="users" components={{main: Users, sidebar: UsersSidebar}}>
See the doc here :
https://github.com/ReactTraining/react-router/blob/v3/docs/API.md#named-components
In v4, according to the docs, you can render multiple components like this:
<Route path='/some-path' render={() =>
<Fragment>
<FirstChild />
<SecondChild />
</Fragment>
} />
Instead of using div's you can use Fragments.
`
<Route path='/some-path' render={props =>
<Fragment>
<Child 1/>
<Child 2/>
</Fragment>
} />
`
You can also use Array in latest versions of React-router-dom;
<Route path="groups" element={[<Component1/>,<Component2/>]} />
Will work just fine.
To render multiple components you can do this:
<Route
path="/EditEmployee/:id"
render={(props) =>
<div>
<NavMenu />
<EditEmployee {...props} />
</div>
}
/>
Here I'm passing parameter to specific conponent.
//this is the simplest method to render multiple components and it works for me
<Router>
<Route path="/">
<ListView />
<ListTopBar />
</Route>
</Router>
<Route path='/' element={<><Header /> <Home /></>} />
This worked for me in the latest react router dom v6
Another method is within the render method of route multiple passed components can be created using react.createElement
<Route render ={(props)=>React.createElement(Component1, {...props}},
React.createElement(Component2, {...props}}/>
What worked for me was to wrap the multiple components in a <Fragment> or a <div> as a parent element.
return (
< Router>
<div className="App" >
<Routes>
<Route path='/'
element={
<Fragment>
< NavBar />
< NewsLetterCard />
< TestimonialsCard />
< ServicesCard />
< ContactsCard />
< Footer />
</Fragment>
}
/>
</Routes>
</div>
</Router>
);
}
For v6, where you are using Routes instead of Switch to render your components. This works:
<Router>
<Routes>
<Route path='/' element={<><Child1/> <Child2/></>} />
</Routes>
</Router>
But for v5, this works:
<Router>
<Switch>
<Route path="/">
<Child1/>
<Child2/>
</Route>
This seem to work for me, I needed to add canvas animation component as background under homepage ("/") only:
import Page from 'pages/Page';
import Blog from 'pages/Blog';
import Post from 'pages/Post';
import Category from 'pages/Category';
import CanvasParticles from 'components/canvas/CanvasParticles';
...
<Routes>
{['/', '/:slug'].map((path, index) => {
return path === '/' ? (
<Route
exact
path={path}
element={[<CanvasParticles />, <Page />]}
key={index}
/>
):(
<Route path={path} element={<Page />} key={index} />
);
})}
<Route exact path="/blog" element={<Blog />}></Route>
<Route path="/blog/:slug" element={<Post />}></Route>
<Route path="/category/:slug" element={<Category />}></Route>
</Routes>
click on this you can view a image v6 feature : this is the simplest method to render multiple components and it works for me
Main Concept is to you should wrap with element
<Route path="/" element={<> </>}
or
wrap with in Fragment
<Route path="/" element={ }

Categories