Giter Site home page Giter Site logo

Comments (5)

diegohaz avatar diegohaz commented on April 30, 2024 16

Why templates are good practice?

image

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:

image

But, on your HomePage, you don't want to render that because you are already rendering it on your Hero component:

image

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.

diegohaz avatar diegohaz commented on April 30, 2024 9

@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.

maxguzenski avatar maxguzenski commented on April 30, 2024

Hi,
I dont use Arc, even atomic design, but I think that in react world, replace page/templates by Environment/Ecosystem make more sense.

https://medium.com/tobikomu/atomic-components-managing-dynamic-react-components-using-atomic-design-part-1-5f07451f261f#.gx9btbf6t

from arc.

diegohaz avatar diegohaz commented on April 30, 2024

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:

  1. In that way, your ecosystems (or smart components that groups organisms) will not be pure components, making it harder to test;
  2. 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 a FacebookLoginButton 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).
    image
    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.
  3. 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.

jlmitch5 avatar jlmitch5 commented on April 30, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.