# Understanding Mars Theme

Mars theme is our starter theme and is installed by default on `frontity create`. Here we'll explain how [`@frontity/mars-theme`](https://github.com/frontity/frontity/tree/dev/packages/mars-theme) works.

> If you yet don't understand the structure of a Frontity project, please read our guide [Understanding a Frontity project](https://gitbook-docs.frontity.org/guides/understanding-mars-theme).

{% hint style="info" %}

{% endhint %}

Have a look at this Frontity Talk where we talk about the `mars-theme`:

* 📺 [Frontity Talks 2020-04 - mars-theme \[27:52\]](https://www.youtube.com/watch?v=e6n1j4gwFjQ\&t=1672s)

## Frontity Utilities

Utilities are those libraries that are part of the Frontity core and need to be exposed to us in order to successfully develop a theme that integrates completely with Frontity. All those utilities are exposed in the`frontity` package.

For example, our state manager `@frontity/connect` exposes a utility called `connect` to wrap our React components so we can access the Frontity store from them. To avoid us the need to remember lots of packages and dependencies, we can import `connect` and other libraries like this:

```jsx
import { connect, styled } from "frontity";

const HelloWorld = () => <Container>Hello World!</Container>;

export default connect(HelloWorld);

const Container = styled.div`
  background: blue;
  color: white;
`;
```

As you can see in the example above, we are accessing also `styled` from `frontity`. In this case `frontity` is just exposing the API of `@emotion/styled`, and it does this with other libraries like `react-helmet`, so you get everything that you'd usually need in just one line.

## Exports

The extension itself can be an object or a function that returns that object. You can see the object structure explained in the following code, along with what we are exporting in `mars-theme`:

```typescript
import Theme from "./components/theme";

const marsTheme = {
  // The name of the extension.
  name: "@frontity/mars-theme",
  // The React components that will be rendered.
  roots: {
    theme: Theme,
  },
  // The default state that the extension needs to create in order to work.
  state: {
    theme: {
      menu: [],
      featured: {
        showOnList: false,
        showOnPost: false,
      },
    },
  },
  // The actions that the extension needs to create in order to work.
  // In our case, `mars-theme` doesn't export any actions.
  actions: {},
  // The libraries that the extension needs to create in order to work.
  // In our case, `mars-theme` doesn't export any actions.
  libraries: {},
};

export default marsTheme;
```

In each part of the exported object, what the extension defines needs to be inside its `namespace`. In our case, all the things we are defining are inside the `theme` namespace, but if our theme implemented, for example, a comments solution, that state, actions, etc., should be defined inside the `comments` namespace. So, in the case of `roots`, it would be something like:

```typescript
import Theme from './components/theme';
import Comments from './components/comments';

const extension = {
  ...
  roots: {
    theme: Theme,
    comments: Comments,
  },
  ...
};
```

## Building the theme

There are some steps that we need to go through in order to have our theme working:

### SSR populated

First of all, we want our server-side rendering to be equal to our client-side rendering to not harm the UX and SEO. In order to do this, we are going to use an action called `beforeSSR`. This action will be run by `@frontity/core` before the server-side render is generated by React and it's the best place to request the data we need from our WP:

We are doing this in our `src/index.js` file:

```javascript
const marsTheme = {
  name: "@frontity/mars-theme",
  roots: { ... },
  state: { ... },
  actions: {
    theme: {
      beforeSSR: async ({ state, actions }) => {
        // We fetch the initial link.
        await actions.source.fetch(state.router.link);
        // NOTE: This is not needed if autoFetch is activated in your router.
      }
    }
  }
};
```

Now that we have the data we need to render our app, we can start writing some React. All the components described below can be found inside `src/components`.

### Theme component

Our main React component will be `Theme`, where we are deciding what kind of view to render, and in order for that component to access the store, we need to wrap it with the `connect` function. Once it's wrapped, we can access `state` and `actions` directly from the props. In this case, we are using `state.source.get()` to retrieve info about what kind of content should be rendered in the current path. If it happens to be an archive, we will render the `<List />` component, if a post type, the `<Post />` and if for some reason `wp-source` couldn't retrieve the data from our WP, we will render a 404 page.

Here you have the code of `Theme` with some comments:

{% code title="index.js" %}

```jsx
import React from "react";
import {
  // Modules from `@emotion/core` and `@emotion/styled`.
  Global,
  css,
  styled,
  // Module from `@frontity/connect`.
  connect,
  // Alias for `Helmet` from `react-helmet`.
  Head
} from "frontity";
import Header from "./header";
import List from "./list";
import Post from "./post";
import Page404 from "./page404.js";

const Theme = ({ state }) => (
  <>
    // Adding some elements to <head>
    // with `react-helmet`.
    <Head>
      <title>{state.frontity.title}</title>
      <html lang="en" />
    </Head>
    // Adding global styles to our app.
    <Global styles={globalStyles} />
    // Just rendering the Header component.
    <HeadContainer>
      <Header />
    </HeadContainer>
    <Body>
      // Here is where we use our `state.source.get()` to decide
      // what component we'll render.
      {state.source.get(state.router.link).isArchive && <List />}
      {state.source.get(state.router.link).isPostType && <Post />}
      {state.source.get(state.router.link).is404 && <Page404 />}
    </Body>
  </>
);

export default connect(Theme);
```

{% endcode %}

Between the `Post` component and the `List` component there are a bunch of different things going on here. I'll start with `List`.

### List component

It is exported from `list/index.js`. There, we are using `loadable` from `frontity` (which is actually an alias for the `default` export of `@loadable/components`) to split the code of our `List` component, so it won't be loaded if a user access directly to a `Post` view, and instead the code will be requested when the user clicks on a list view. This is helpful to reduce the loading times and times to interactive of our site. The less code we have, the less time the browser spends evaluating it.

{% code title="list/index.js" %}

```javascript
import { loadable } from "frontity";

// Codesplit the list component so it's not included if the users
// load a post directly.
export default loadable(() => import("./list"));
```

{% endcode %}

Now, our `List` component is the responsible to render a list of posts, and for that it needs to know what posts to render. We are using `state.source.get(link)` and its `items` field.

{% code title="list/list.js" %}

```jsx
const List = ({ state }) => {
  // Get the data of the current list.
  const data = state.source.get(state.router.link);

  return (
    <Container>
      {/* If the list is a taxonomy, we render a title. */}
      {data.isTaxonomy && (
        <Header>
          {data.taxonomy}: {state.source[data.taxonomy][data.id].name}
        </Header>
      )}

      {/* If the list is an author, we render a title. */}
      {data.isAuthor && (
        <Header>Author: {state.source.author[data.id].name}</Header>
      )}

      {/* Iterate over the items of the list. */}
      {data.items.map(({ type, id }) => {
        const item = state.source[type][id];
        // Render one Item component for each one.
        return <Item key={item.id} item={item} />;
      })}
      <Pagination />
    </Container>
  );
};
```

{% endcode %}

The last detail we are going to explain is how we are doing pagination on `List`.

We are getting the total of pages for that list from `state.source.get(link)` and we are checking if we are either in the first one, the last one, or in the middle. Using the React hook `useEffect` we are prefetching the next page when the component mounts, so in the case the user goes there, he doesn't have to wait for the response from the WP REST API.

Depending on the page we are at the moment, we render different links to travel through the list. For that we are using our own `Link` component, which accepts the same parameters as `actions.source.fetch()` or `actions.router.set()`.

{% code title="list/pagination.js" %}

```javascript
const Pagination = ({ state, actions, libraries }) => {
  const { totalPages } = state.source.get(state.router.link);
  const { path, page, query } = libraries.source.parse(state.router.link);

  const isThereNextPage = page < totalPages;
  const isTherePreviousPage = page > 1;

  const nextPageLink = libraries.source.stringify({
    path,
    page: page + 1,
    query,
  });

  const prevPageLink = libraries.source.stringify({
    path,
    page: page - 1,
    query,
  });

  useEffect(() => {
    // Fetch the next page if it hasn't been fetched yet.
    if (isThereNextPage) actions.source.fetch(nextPageLink);
  }, []);

  return (
    <div>
      {isThereNextPage && (
        <Link link={nextPageLink}>
          <em>← Older posts</em>
        </Link>
      )}
      {isTherePreviousPage && isThereNextPage && " - "}
      {isTherePreviousPage && (
        <Link link={prevPageLink}>
          <em>Newer posts →</em>
        </Link>
      )}
    </div>
  );
};
```

{% endcode %}

### Post component

There is something new here, that we haven't done on `List`. We are doing a preload of the `List` component (as it is a dynamic component and we don't have that code yet). Once we have our site rendered and working, we preload the code for `List`, so the user won't need to wait for it later if she decides to visit a list of posts.

{% code title="post.js" %}

```javascript
import List from './list';

const Post = ({ state, actions }) => {
  const data = state.source.get(state.router.link);
  const post = state.source[data.type][data.id];
  // Get the author.
  const author = state.source.author[post.author];
  const date = new Date(post.date);

  useEffect(() => {
    actions.source.fetch("/");
    // Here is where we are preloading the List component.
    // This will run only on mount.
    List.preload();
  }, []);

  return data.isReady ? (
    <Container>
      { ... }
    </Container>
  ) : null;
};
```

{% endcode %}

### Defining the theme state

The last thing that might need to be explained is how we define `state` for our extension in order to use it within React and be able to set it with a `frontity.settings` file in a Frontity project.

In `mars-theme` we are defining the following `state`:

```javascript
// src/html/index.js

const marsTheme = {
  ...,
  state: {
    theme: {
      // This field will be used in our Nav bar.
      // Here we are defining the default value.
      menu: [],
      featured: {
        showOnList: false,
        showOnPost: false
      }
    }
  }
};
```

And we are using it as shown below:

{% code title="nav.js" %}

```jsx
const Nav = ({ state }) => (
  <Container>
    {state.theme.menu.map(([name, link]) => (
      <Item key={name} isSelected={state.router.link === link}>
        <Link link={link}>{name}</Link>
      </Item>
    ))}
  </Container>
);
```

{% endcode %}

And when we create a new Frontity project where our theme is installed, that state can be changed in `frontity.settings.js`:

```javascript
const settings = {
  ...,
  packages: [
    ...,
    {
      name: "@frontity/mars-theme",
      state: {
        theme: {
          // Here is where the owner of the project can
          // set the values of the `mars-theme` state.
          ...,
          menu: [
            ["Home", "/"],
            ["Nature", "/category/nature/"],
            ["Travel", "/category/travel/"],
            ["Japan", "/tag/japan/"],
            ["About Us", "/about-us/"]
          ],
        }
      }
    }
  ]
};
```

{% hint style="info" %}
Still have questions? Ask [the community](https://community.frontity.org/)! We are here to help 😊
{% endhint %}
