refactored Navbar component
This commit is contained in:
@@ -1,108 +1,94 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { useState, useEffect } from 'react'
|
||||||
import { NavLink } from 'react-router-dom';
|
import { NavLink } from 'react-router-dom'
|
||||||
import _ from 'lodash';
|
import _ from 'lodash'
|
||||||
import { withRouter } from 'react-router-dom';
|
import { withRouter } from 'react-router-dom'
|
||||||
|
|
||||||
import axios from '../axios-movies';
|
import { useScroll } from '../hooks/useScroll'
|
||||||
import SearchLogo from '../static/images/search-icon.svg';
|
import { useDebounce } from '../hooks/useDebounce'
|
||||||
import NetflixLogo from '../static/images/Netflix_Logo_RGB.png';
|
import axios from '../axios-movies'
|
||||||
import BellLogo from '../static/images/bell-logo.svg';
|
import SearchLogo from '../static/images/search-icon.svg'
|
||||||
import DropdownArrow from '../static/images/drop-down-arrow.svg';
|
import NetflixLogo from '../static/images/Netflix_Logo_RGB.png'
|
||||||
import DropdownContent from "../components/DropdownContent";
|
import BellLogo from '../static/images/bell-logo.svg'
|
||||||
|
import DropdownArrow from '../static/images/drop-down-arrow.svg'
|
||||||
|
import DropdownContent from '../components/DropdownContent'
|
||||||
|
|
||||||
class Navbar extends Component {
|
const Navbar = (props) => {
|
||||||
constructor(props) {
|
const [userInput, setUserInput] = useState('')
|
||||||
super(props)
|
const [scrollDimensions] = useScroll()
|
||||||
this.state = {
|
const { scrollY } = scrollDimensions
|
||||||
scrolling: false,
|
|
||||||
userInput: ''
|
const debouncedUserInput = useDebounce(userInput, 500)
|
||||||
|
|
||||||
|
const onChange = async (event) => {
|
||||||
|
setUserInput(event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onSearchUserInputHandler(userInput)
|
||||||
|
if (debouncedUserInput) {
|
||||||
|
onSearchUserInputHandler(debouncedUserInput)
|
||||||
}
|
}
|
||||||
// use to debounce api call
|
}, [debouncedUserInput])
|
||||||
this.makeAipCall = _.debounce(this.makeAipCall, 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
const onSearchUserInputHandler = async (searchItem) => {
|
||||||
window.addEventListener('scroll', this.handleScroll);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
window.removeEventListener('scroll', this.handleScroll);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** changes the scrolling state depending on the Y-position */
|
|
||||||
handleScroll = () => {
|
|
||||||
if (window.scrollY === 0) {
|
|
||||||
this.setState({ scrolling: false });
|
|
||||||
}
|
|
||||||
else if (window.scrollY > 50) {
|
|
||||||
this.setState({ scrolling: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onChange = async (event) => {
|
|
||||||
await this.setState({ userInput: event.target.value })
|
|
||||||
const { userInput } = this.state
|
|
||||||
|
|
||||||
await this.makeAipCall(userInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Make API call as soon as the user starts typing. */
|
|
||||||
makeAipCall = async (searchItem) => {
|
|
||||||
if (searchItem.length === 0) {
|
if (searchItem.length === 0) {
|
||||||
this.props.history.push('/')
|
props.history.push('/')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const url = `/search/multi?api_key=${process.env.API_KEY}&language=en-US&include_adult=false&query=${searchItem}`;
|
const url = `/search/multi?api_key=${process.env.API_KEY}&language=en-US&include_adult=false&query=${searchItem}`
|
||||||
const response = await axios.get(url);
|
const response = await axios.get(url)
|
||||||
const results = response.data.results;
|
const results = response.data.results
|
||||||
this.props.history.push({
|
console.log('called api...')
|
||||||
|
props.history.push({
|
||||||
pathname: '/search',
|
pathname: '/search',
|
||||||
movieRows: results,
|
movieRows: results,
|
||||||
userInput: searchItem
|
userInput: searchItem,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onLogoClick = () => {
|
const onLogoClick = () => {
|
||||||
// reset input state
|
setUserInput('')
|
||||||
this.setState({ userInput: '' })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
const { scrolling } = this.state;
|
<nav className={'navigation ' + (scrollY > 50 ? 'black' : '')}>
|
||||||
|
<ul className='navigation__container'>
|
||||||
|
<NavLink to='/' onClick={() => onLogoClick()}>
|
||||||
|
<img
|
||||||
|
className='navigation__container--logo'
|
||||||
|
src={NetflixLogo}
|
||||||
|
alt=''
|
||||||
|
/>
|
||||||
|
</NavLink>
|
||||||
|
<DropdownArrow className='navigation__container--downArrow-2'></DropdownArrow>
|
||||||
|
<div className='navigation__container-link pseudo-link'>Home</div>
|
||||||
|
<div className='navigation__container-link pseudo-link'>TV Shows</div>
|
||||||
|
<div className='navigation__container-link pseudo-link'>Movies</div>
|
||||||
|
<div className='navigation__container-link pseudo-link'>
|
||||||
|
Recently Added
|
||||||
|
</div>
|
||||||
|
<div className='navigation__container-link pseudo-link'>My List</div>
|
||||||
|
|
||||||
return (
|
<div className='navigation__container--left'>
|
||||||
<nav className={"navigation " + (scrolling ? "black" : "")} >
|
<SearchLogo className='logo' />
|
||||||
<ul className="navigation__container">
|
<input
|
||||||
<NavLink to="/" onClick={() => this.onLogoClick()}>
|
value={userInput}
|
||||||
<img className="navigation__container--logo" src={NetflixLogo} alt="" />
|
onChange={(event) => onChange(event)}
|
||||||
</NavLink>
|
className='navigation__container--left__input'
|
||||||
<DropdownArrow className="navigation__container--downArrow-2"></DropdownArrow>
|
type='text'
|
||||||
<div className="navigation__container-link pseudo-link">Home</div>
|
placeholder='Title, genres, people'
|
||||||
<div className="navigation__container-link pseudo-link">TV Shows</div>
|
/>
|
||||||
<div className="navigation__container-link pseudo-link">Movies</div>
|
</div>
|
||||||
<div className="navigation__container-link pseudo-link">Recently Added</div>
|
|
||||||
<div className="navigation__container-link pseudo-link">My List</div>
|
|
||||||
|
|
||||||
<div className="navigation__container--left">
|
<div className='navigation__container-link pseudo-link'>KIDS</div>
|
||||||
<SearchLogo className="logo" />
|
<div className='navigation__container-link pseudo-link'>DVD</div>
|
||||||
<input
|
<BellLogo className='navigation__container--bellLogo' />
|
||||||
value={this.state.userInput}
|
|
||||||
onChange={() => this.onChange(event)}
|
|
||||||
className="navigation__container--left__input"
|
|
||||||
type="text"
|
|
||||||
placeholder="Title, genres, people" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="navigation__container-link pseudo-link">KIDS</div>
|
<DropdownContent />
|
||||||
<div className="navigation__container-link pseudo-link">DVD</div>
|
<DropdownArrow className='navigation__container--downArrow' />
|
||||||
<BellLogo className="navigation__container--bellLogo" />
|
</ul>
|
||||||
|
</nav>
|
||||||
<DropdownContent />
|
)
|
||||||
<DropdownArrow className="navigation__container--downArrow" />
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRouter(Navbar);
|
export default withRouter(Navbar)
|
||||||
|
|||||||
25
src/hooks/useDebounce.js
Normal file
25
src/hooks/useDebounce.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
|
||||||
|
export const useDebounce = (value, delay) => {
|
||||||
|
// State and setters for debounced value
|
||||||
|
const [debouncedValue, setDebouncedValue] = useState(value)
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
() => {
|
||||||
|
// Update debounced value after delay
|
||||||
|
const handler = setTimeout(() => {
|
||||||
|
setDebouncedValue(value)
|
||||||
|
}, delay)
|
||||||
|
|
||||||
|
// Cancel the timeout if value changes (also on delay change or unmount)
|
||||||
|
// This is how we prevent debounced value from updating if value is changed ...
|
||||||
|
// .. within the delay period. Timeout gets cleared and restarted.
|
||||||
|
return () => {
|
||||||
|
clearTimeout(handler)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[value, delay] // Only re-call effect if value or delay changes
|
||||||
|
)
|
||||||
|
|
||||||
|
return debouncedValue
|
||||||
|
}
|
||||||
26
src/hooks/useScroll.js
Normal file
26
src/hooks/useScroll.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
|
||||||
|
const scrollY = window.scrollY || document.documentElement.scrollTop
|
||||||
|
const scrollX = window.scrollY || document.documentElement.scrollWidth
|
||||||
|
|
||||||
|
export const useScroll = () => {
|
||||||
|
const [scrollDimensions, setScrollDimensions] = useState({ scrollY, scrollX })
|
||||||
|
|
||||||
|
const deriveScrollDimensions = () => {
|
||||||
|
const scrollY = window.scrollY || document.documentElement.scrollTop
|
||||||
|
const scrollX = window.scrollY || document.documentElement.scrollWidth
|
||||||
|
|
||||||
|
setScrollDimensions({ scrollY, scrollX })
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
deriveScrollDimensions()
|
||||||
|
window.addEventListener('scroll', deriveScrollDimensions)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', deriveScrollDimensions)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return [scrollDimensions]
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export default function NotFound() {
|
const NotFound = () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>NOT FOUND</h1>
|
<h1>NOT FOUND</h1>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default NotFound
|
||||||
Reference in New Issue
Block a user