[WK7-Th] Dumb UI component - tradeoffs of solutions, zIndex, git pull --rebase
1. Waking up
Yeah maybe I prefer wfh all the time. Just easier to wake up and manage time, and not feel tired all the time. I thought I always preferred office, but meh commute time and all-day parking fee acts as a deterrent to office commute.
There's additional factor that I like my home chair. I really enjoy using my new chair (Aeron size B)! It really makes you want to sit, and in a way it gives sitting-gasm to your spine. Idk how I might explain it, but yeah it's definitely worth it. Got it about last week or last last week I think? (Friday)
2. Dumb UI component
There's this notion of 'Dumb UI component' when it comes to building frontend components. In essence, Dumb UI component is resuable, not dependent on libraries, does not fetch data, receives everything through props. Smart UI component on the other hand would try to do many things, which makes it coupled with the context for which it is used.
The product team that I was working in would stress the paradigm of keeping every UI components dumb. That way, it is reusable even outside of the product for which it is made.
In my last post (refer to section 4), I was working on displaying 'Skip to content' at the top:
Previously, that 'Skip to content' would have appeared under the yellow announcement bar. There were several solutions to this. Let's look at the original code:
// SkipToMain.js in ui-components package
const css = `
[skip-link] {
// properties to make this box invisible (height 1px, margin -1px...)
}
[skip-link]:focus {
// when it's focused, it should appear as a box that has a link
}
`
const SkipToMain = ({id, label})=>(
<>
<style>{css}</style>
<a href={`#${id}`} skip-link="" tabIndex={0}>
{label}
</a>
</>
)
2.1 Solution 1: inline css z-index
// SkipToMain.js in ui-components package
const css = `
//...
[skip-link]:focus {
//...
z-index: 2000
}
`
const SkipToMain = ...
The problems are:
- Use of arbitrary number (magic number) which has no reason for its particular value(2000). There should be consistent methodology in generating such numbers, but there's no apparent method for that.
- SkipToMain component should be dumb, meaning that nothing about z-index should even be considered at that component level. Why does having z-index make it a non-dumb component? It's because z-index concerns with how it positions relative to others in a webpage, but that naturally makes the component coupled with context for which it is used, which results in less resuable component.
2.2 Solution 2: remove magic number with material ui theme
const SkipToNavStyles = (theme)=>{
dataSkipNavLink:{
// styling when not on focus
// ...
// mui pseudo selector
'&:focus':{
// styling when on focus
// announcementBanner had zIndex: theme.zIndex.modal + 1
zIndex: theme.zIndex.modal + 2
}
}
}
const SkipToNav = ()=>{
const classes = makeStyles(SkipToNavStyles)()
return (<>
<a classNames={classes.dataSkipNavLink} ...>
</a>
<>)
}
This is better because it uses theme.zIndex.modal+2 instead of 2000 for zIndex. However, the fact that we have zIndex in that component means it's not a dumb ui component.
2.3 Solution 3-1: feed from above, but keep inline styling of SkipToMain
So we have a package that looks like xxx-application (xxx being our product name), and that has a top level component called 'App' (app.js).
// very simplified view of App component, top level component
import {useTheme} from '@material-ui/core/styles'
function App({...}){
const theme = useTheme()
return (<>
<div style={{zIndex: theme.zIndex.modal + 2}}>
<SkipToMain>
</div>
<main>...</main>
</>
<>)
}
This keeps SkipToMain component dumb, and all the while avoids magic number of 2000. Good thing is that it effectively just wraps around the component. We didn't need to make change to SkipToMain at all!
Extra divs are ugly though, and here's how we might solve it (not that the next solution is definitely better, but it's an option that I went with)
2.4 Solution 3-2: top level styling fed to children (SkipToMain)
// very simplified view of App component, top level component
import {appStyles} from '../appStyles'
function App({...}){
const classes = makeStyles(appStyles)()
return (<>
<SkipToMain className={classes.dataSkipNavLink}>
<main>...</main>
</>
<>)
}
// appStyles.js
export const appStyles = (theme)=>{
dataSkipNavLink:{
'&:focus':{
zIndex: theme.zIndex.modal
}
}
// other styles...
}
// SkipToMain.js
const SkipToMain = ({..., className})=>(
<>
<a className={className}>...</a>
<>
)
It's very similar to solution 3-1, and to be honest, I'm not sure which one is better. But it definitely has advantage that you don't introduce extra divs.
3. Git Rebase
I think I understand git pull --rebase origin master now.