In this article, we will be writing a simple custom React hook which will be based on React useEffect hook from react and allow us to control background page color. For example, to enable dark mode.
yarn create react-app dark-background
cd dark-background
By default create-react-app project background is dark already so we need to disable it.
Navigate to the App.css and comment line with background-color of the .App-header CSS class.
/* src/App.css */
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
}
.App-header {
/* background-color: #282c34; */
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #09d3ac;
}
Do the yarn start and verify that the starting page loads with the white background color.
I'm going to create a hooks folder under src with index.js and useDarkBody.js files.
// hooks/useDarkBody.js
import { useEffect } from 'react'
function useGreyBody() {
useEffect(() => {
document.body.style.backgroundColor = '#282c34'
return () => {
document.body.style.backgroundColor = '#fff'
}
})
}
export default useGreyBody
When used useGreyBody() will set a page background color to #282c34 otherwise color will be #fff.
In order to use our custom hook whatever we want from the hooks/ folder let's our hook as default export from hooks/index.js:
// hooks/index.js
export { default as useDarkBody } from './useDarkBody'
Navigate to the App.js and invoke useDarkBody() before render function:
// src/App.js
import React from 'react'
import logo from './logo.svg'
import './App.css'
import { useDarkBody } from './hooks'
function App() {
useDarkBody()
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
)
}
export default App
yarn start do start the app an verify that color is now changed to dark. You can use this hook whenever need in other components as you wish.
Congrats! We've created a custom re-usable hook which does one simple thing :)
Nice thing is that you can create tests for your hooks independently. Under hooks/ let's create a test file useDarkBody.spec.js:
import React from 'react'
import { mount } from 'enzyme'
import useDarkBody from './useDarkBody'
describe('useDarkBody', () => {
it('should set background body color to dark when invoked.', () => {
expect(document.body.style.backgroundColor).toMatchSnapshot()
const Component = () => {
useDarkBody()
return null
}
mount(<Component />)
expect(document.body.style.backgroundColor).toMatchSnapshot()
})
it('should revert to white when the component is unmounted.', () => {
const Component = () => {
useDarkBody()
return null
}
const component = mount(<Component />)
expect(document.body.style.backgroundColor).toMatchSnapshot()
component.unmount()
expect(document.body.style.backgroundColor).toMatchSnapshot()
})
})
In order to run the tests add Enzyme as a dev dependency to our project with its adapter and test-renderer by running:
yarn add -D enzyme enzyme-adapter-react-16 react-test-renderer
Under src create a file called setupTests.js:
// src/setupTests.js
import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
configure({ adapter: new Adapter() })
Run the tests with yarn test and all should be green :)
