This content originally appeared on flaviocopes.com and was authored by flaviocopes.com
This post is part of a new series where we build a clone of Airbnb with Next.js. See the first post here.
- Part 1: Let’s start by installing Next.js
- Part 2: Build the list of houses
- Part 3: Build the house detail view
- Part 4: CSS and navigation bar
- Part 5: Start with the date picker
- Part 6: Add the sidebar
- Part 7: Add react-day-picker
- Part 8: Add the calendar to the page
- Part 9: Configure the DayPickerInput component
- Part 10: Sync the start and end dates
- Part 11: Show the price for the chosen dates
- Part 12: Login and signup forms
Let’s first hide the form, which now loads by default on every page load.
We just need to default to false
the hooks we defined in components/Layout.js
.
Instead of:
const [showModal, setShowModal] = useState(true)
const [showLoginModal, setShowLoginModal] = useState(true)
We set:
const [showModal, setShowModal] = useState(false)
const [showLoginModal, setShowLoginModal] = useState(false)
Now, we are going to enable the modals when these event occur:
- the Sign Up or Log in links are clicked in the nav bar, in
components/Header.js
- the Reserve button in the
pages/houses/[id].js
component is clicked after a user chooses a set of dates
It’s just 3 different places, but we can immediately spot a problem: the state of the modals is being centralized and we’d need to pass around both the state and the functions to update it, too much.
And we’re just starting out.
Soon we’ll have to manage the user logins, and that would also need more state management.
So, we’re going to add one library to our project, one library that helps us manage the state easily.
There are solutions in React that are quite complicated, and I’m sure they are useful in many scenarios, but I like to keep my code as simple as possible.
Simple is understandable.
Simple is beautiful.
Complexity should be avoided at all costs, and if possible hidden away in libraries that expose a simple interface to us.
It’s the case of this library, which is called easy-peasy
.
Go take a look at their website https://easy-peasy.now.sh/ and then come back.
First of all, stop the Next.js server and run
npm install easy-peasy
to install the library.
Then restart the Next.js server with npm run dev
.
Now, first of all we need to create a store. The store is the place where we’ll store our state, and the functions needed to modify it.
Create the store in the file store.js
in the root of the project, with this content:
store.js
import { createStore, action } from 'easy-peasy'
export default createStore({})
We’ll add more things to this file later.
Now we need to do one thing - we need to wrap all the Next.js app into a component provided by easy-peasy, and the way Next.js provides us to do it is to create a file called _app.js
in the pages
folder.
Open pages/_app.js
, which now has this content:
pages/_app.js
import App from 'next/app'
import '../styles/globals.css'
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
Now we’re going to import the store we defined in store.js
, and we also import the StoreProvider
component from easy-peasy
.
With this component, we wrap the default Component
and we pass the store as a prop to it:
pages/_app.js
import '../styles/globals.css'
import { StoreProvider } from 'easy-peasy'
import store from '../store'
function MyApp({ Component, pageProps }) {
return (
<StoreProvider store={store}>
<Component {...pageProps} />
</StoreProvider>
)
}
export default MyApp
This operation makes now our store available in every component of the app.
So let’s now centralize the state we added to components/Layout.js
in the last lesson, to the store.js
file.
If you think we wasted some time in the last lesson, we didn’t - most of the times those implementations are iterative. You first try the simplest solution, and then move on to more complex scenarios as the needs evolve. Now we know what things we need.
store.js
import { createStore, action } from 'easy-peasy'
export default createStore({
modals: {
showModal: false,
showLoginModal: false,
showRegistrationModal: false,
setShowModal: action((state) => {
state.showModal = true
}),
setHideModal: action((state) => {
state.showModal = false
}),
setShowLoginModal: action((state) => {
state.showModal = true
state.showLoginModal = true
state.showRegistrationModal = false
}),
setShowRegistrationModal: action((state) => {
state.showModal = true
state.showLoginModal = false
state.showRegistrationModal = true
})
}
})
We defined a modals
object with some properties, and 4 actions, which we’ll use in our app components to change the state.
Let’s start from the Header.js
component. When our Log in and Sign up buttons are clicked, we want to activate the correct modal.
In there, we import useStoreActions
to be able to access the store functions:
import { useStoreActions } from 'easy-peasy'
and inside the component we initialize those actions to be used:
const setShowLoginModal = useStoreActions(
(actions) => actions.modals.setShowLoginModal
)
const setShowRegistrationModal = useStoreActions(
(actions) => actions.modals.setShowRegistrationModal
)
Now we can call setShowLoginModal
and setShowRegistrationModal
as regular functions, and this is what we’re going to do:
<nav>
<ul>
<li>
<a href="#" onClick={() => setShowRegistrationModal()}>
Sign up
</a>
</li>
<li>
<a href="#" onClick={() => setShowLoginModal()}>
Log in
</a>
</li>
</ul>
</nav>
Great! Now switch to the components/Layout.js
file. In there, we import the useStoreState
and useStoreActions
from easy-peasy
.
import { useStoreState, useStoreActions } from 'easy-peasy'
useStoreState
is new to us, and we’ll use it to access the store state properties.
Inside the Layout component function body, let’s initialize a few variables:
const showModal = useStoreState((state) => state.modals.showModal)
const showLoginModal = useStoreState((state) => state.modals.showLoginModal)
const showRegistrationModal = useStoreState(
(state) => state.modals.showRegistrationModal
)
const setHideModal = useStoreActions((actions) => actions.modals.setHideModal)
const setShowRegistrationModal = useStoreActions(
(actions) => actions.modals.setShowRegistrationModal
)
const setShowLoginModal = useStoreActions(
(actions) => actions.modals.setShowLoginModal
)
The first 3 are properties, which we’ll use to determine if modals should be shown or not, just like we did before using the properties generated using the useState
hook:
{
showModal && (
<Modal close={() => setHideModal()}>
{showLoginModal && (
<LoginModal
showSignup={() => {
setShowRegistrationModal()
}}
/>
)}
{showRegistrationModal && (
<RegistrationModal
showLogin={() => {
setShowLoginModal()
}}
/>
)}
</Modal>
)
}
See, I called setHideModal()
. Before I had setShowModal(false)
, but I think setHideModal()
is clearer. We could have passed a parameter as part of our easy-peasy
action, too.
And instead of calling
setShowRegistrationModal(true)
setShowLoginModal(false)
I called
setShowRegistrationModal()
because we abstract away all the logic in the store. We don’t need to manage all the details, we just tell it to show the registration modal.
Same for the login modal.
The other part where we’ll show a modal, as we said, is the Reserve button in the pages/houses/[id].js
component.
Users click the button when they finally chose the dates for the stay, and we can go on with the purchase flow.
So let’s now switch to the pages/houses/[id].js
file.
In there, we first import useStoreActions
:
import { useStoreActions } from 'easy-peasy'
pages/houses/[id].js
and in the component body we initialize the setShowLoginModal
action:
const setShowLoginModal = useStoreActions(
(actions) => actions.modals.setShowLoginModal
)
and finally we call it when the button is clicked:
<button
className="reserve"
onClick={() => {
setShowLoginModal()
}}
>
Reserve
</button>
Awesome! Our modal should be correctly working now. We’re ready to start implementing the registration functionality now.
Oh, one thing to note: I changed the links I previously defined as <a href="javascript:;" ...
to <a href="#" ...
because I noticed that React complained about using javascript:
URLs in the DevTools console, about them being deprecated (although they are a perfectly find JavaScript feature). A reminder to always check the DevTools if React tells us something is wrong.
This content originally appeared on flaviocopes.com and was authored by flaviocopes.com
flaviocopes.com | Sciencx (2021-12-13T05:00:00+00:00) Airbnb clone, activate the modal. Retrieved from https://www.scien.cx/2021/12/13/airbnb-clone-activate-the-modal/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.