Comments (5)
Why templates are good practice?
Assuming we have different pages in our app and they share a similar layout, we have our first problem to solve: how to share the layout?
What I did in the past, which is what I see most people doing, is rendering the layout on the App
component around the page content (children
) like that:
const App = ({ children }) => (
<div>
<Header />
<div style={{ display: 'flex' }}>
<Sidebar />
<div style={{ flex: 1 }}>{children}</div>
</div>
<Footer />
</div>
)
It works on simple apps. But, let's say that on your Header
you render a SearchBar
component like this:
But, on your HomePage
, you don't want to render that because you are already rendering it on your Hero
component:
How would you solve this with the layout around content approach? Well, what I did was something like this:
const App = ({ children, currentPage }) => (
<div>
<Header hideSearchBar={currentPage === 'Home'} />
<div style={{ display: 'flex' }}>
<Sidebar />
<div style={{ flex: 1 }}>{children}</div>
</div>
<Footer />
</div>
)
I don't need to say how ugly this is. 😄
The solution was removing layout from App
and creating a Layout
component:
const Layout = ({ children, hideSearchBar }) => (
<div>
<Header hideSearchBar={hideSearchBar} />
<div style={{ display: 'flex' }}>
<Sidebar />
<div style={{ flex: 1 }}>{children}</div>
</div>
<Footer />
</div>
)
So, instead of rendering the page inside the layout, I render the layout with the page:
const HomePage = () => (
<Layout hideSearchBar>
Hello World
</Layout>
)
But it wasn't the ideal solution yet. For every possible state in Header
, Sidebar
etc. I would need to also add the property on Layout
to pass it down.
The solution was just giving the space in layout and letting the page to choose the component to render in there:
const Layout = ({ children, header, sidebar, footer }) => (
<div>
{header}
<div style={{ display: 'flex' }}>
{sidebar}
<div style={{ flex: 1 }}>{children}</div>
</div>
{footer}
</div>
)
const HomePage = () => (
<Layout
header={<Header hideSearchBar />}
sidebar={<Sidebar />}
footer={<Footer />}>
Hello World
</Layout>
)
const PostDetailPage = () => (
<Layout
header={<Header />}
sidebar={<Sidebar onlyPrimaryLinks />}
footer={<Footer />}>
Hello World
</Layout>
)
And that Layout
component is actually what a template is.
from arc.
@jlmitch5 Sure. You just need to set it in defaultProps
on the template:
import { Header } from 'components'
...
PageTemplate.defaultProps = {
header: () => <Header />
}
Just make sure to name things properly to not cause any conflicts.
from arc.
Hi,
I dont use Arc, even atomic design, but I think that in react world, replace page/templates by Environment/Ecosystem make more sense.
from arc.
Hi, @maxguzenski. Thank you for the feedback.
I like that article. But I don't think it replaces pages by ecosystems. It just drops the concept of pages, arguing that React apps don't have them (which I disagree), and ecosystems are more like the containers of a redux application, which connect a group of organisms together with a state management system (redux, mobx etc.).
I don't like that approach because:
- In that way, your ecosystems (or smart components that groups organisms) will not be pure components, making it harder to test;
- Not only organisms should be connected to the state. For example, if you have a
FacebookLoginButton
molecule, you want it to perform the Facebook login action wherever it is placed. So, in the redux world, you'll create aFacebookLoginButton
container, which just imports the molecule and pass the state and actions in. In the ecosystem approach, organisms will know too much of what they should not know (like the facebook login action).
In other words, you want to place<FacebookLoginButton />
wherever you want, and it should have the same behavior whenever you click on it. But it makes no sense being an ecosystem. - React apps do have pages. I know that most of a webapp are state changes on a single page, but the concept of pages still exists.
Later I'll write a little about why I believe that the templates are a good practice explaining the problems I had when developing with React and web components in general (Polymer) and how the templates solved them.
from arc.
I think this idea is really cool, but I have a question about trying to make this more DRY. Let's take your example:
const HomePage = () => (
<Layout
header={<Header hideSearchBar />}
sidebar={<Sidebar />}
footer={<Footer />}>
Hello World
</Layout>
)
const PostDetailPage = () => (
<Layout
header={<Header />}
sidebar={<Sidebar onlyPrimaryLinks />}
footer={<Footer />}>
Hello World
</Layout>
)
Would it be possible to reduce the boilerplate in a way that allows you to only include the components that are unique to various pages. In other words:
const HomePage = () => (
<Layout
header={<Header hideSearchBar />} >
Hello World
</Layout>
)
const PostDetailPage = () => (
<Layout
sidebar={<Sidebar onlyPrimaryLinks />} >
Hello World
</Layout>
)
edit: I think it might be if you did something like the following:
const Layout = ({ children, header, sidebar, footer }) => (
<div>
{header || <Header />}
<div style={{ display: 'flex' }}>
{sidebar || <Sidebar />}
<div style={{ flex: 1 }}>{children}</div>
</div>
{footer || <Footer />}
</div>
)
from arc.
Related Issues (20)
- Running from dist HOT 1
- A lot of packages is out of date HOT 2
- Arc ssr (server side) CSS can not loaded. HOT 1
- r
- Error with import components HOT 6
- Looking for a Typescript version of components/index.js HOT 1
- Question about how 'components' is exported in the example project HOT 1
- GraphQl Branch HOT 3
- Updating to webpack 4
- Updating the SSR version to webpack 4 : new webpack config HOT 1
- Implement React Portals HOT 4
- Non root path build
- crashes on heroku, but not locally.
- injectGlobal is not supported
- `process.env` Object in config.js empty on Browser
- change crlf to lf
- Molecule inside molecule
- Discussion: are people still using Atomic design in 2021? HOT 2
- eslint bug
- Mui
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from arc.