How To Theme Your App With React, Redux & SCSS
Tags: react, redux, scss, javascript
Published: 2021-10-26 05:23:57

An opinionated guide on how to theme your react application with SCSS and Redux.
<!-- Explain the raw concept of theming, i.e write different style codes for rach theme -->

## Steps to follow

Create a new app with create-react-app
```bash
npx create-react-app myapp
```

Add structure to your app:
```text
...
src
  store
    theme
      theme.slice.js
      theme.actions.js
    rootReducer
  styles
    _themes.scss
    _themify.scss
  components
    layout
      layout.jsx
      layout.scss
  page
    home
      home.jsx
    about
      about.jsx
  App.js
...
```

Add these packages to the app
```bash
npm i @reduxjs/toolkit redux node-sass react-router-dom react-redux --save
```

Create the theme slice
```js
// theme.slice.js
import { createSlice } from '@reduxjs/toolkit'
import { uiActions } from './ui.actions'

export const uiSlice = createSlice({
  name: 'ui',
  initialState: 'light-theme',
  reducers: uiActions
})

export const { toggleTheme } = uiSlice.actions

export default uiSlice.reducer
```

Create the theme action
```js
// theme.action.js
export const uiActions = {
  toggleTheme: state => {
    console.log(state);
    return state === 'dark-theme' ? 'light-theme' : 'dark-theme';
  }
};
```

Create the reducer
```js
// rootReducer.js
import { configureStore } from '@reduxjs/toolkit'
import uiReducer from './ui/ui.slice'

export default configureStore({
  reducer: {
    ui: uiReducer,
  }
})
```

Create your theme map
```scss
// themes.scss
$themes: (
  light: (
    bg: #f5fcff,
    fg: #002433,
  ),
  dark: (
    bg: #004966,
    fg: #f5fcff,
  ),
);
```

Create the themify @mixin
```scss
// themify.scss
@import 'themes';

@mixin themify($property, $key, $themes: $themes) {
  // Iterate over the themes
  @each $theme, $colors in $themes {
    // Create a selector
    &.#{$theme}-theme,
    .#{$theme}-theme & {
      // Output the declaration
      #{$property}: map-get($colors, $key);
    }
  }
}
```

Create the layout component
```jsx
// layout.jsx
import { useSelector, useDispatch } from "react-redux";
import { toggleTheme } from "../../store/ui/ui.slice";
import './layout.scss';

export default function Layout(props) {

  const theme = useSelector(state => state.ui);
  const dispatch = useDispatch();

  return (
    <>
      <header className={`${theme} container`}>
        <Header />
        <button onClick={() => dispatch(toggleTheme())}>Toggle Theme</button>
      </header>

      <div className={`${theme} container`}>
        {props.children}
      </div>
    </>
  )
}
```

Apply styles to the layout
```scss
// layout.scss
@import "../../assets/style/themify";

header {
  @include themify('background', 'body-bg');
}
```

Now create your pages
```jsx
// home.jsx
import { Layout } from "../../components/layout/layout";

export default function Home() {
  return (
    <Layout>
      <section>
        Home Page
      </section>
    </Layout>
  )
}
```

```jsx
// about.jsx
import { Layout } from "../../components/layout/layout";

export default function About() {
  return (
    <Layout>
      <section>
        About Page
      </section>
    </Layout>
  )
}
```

Create routes for the application
```js
// App.js
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Home from './pages/home/home';
import About from './pages/about/about';

function App() {

  return (
    <Router>
      <Switch>
        <Route exact path='/' component={Home} />
        <Route exact path='/tasks' component={About} />
      </Switch>
    </Router>
  );
}

export default App;
```

The output:
Run the output on codepen.

Thanks.