Last active
June 7, 2023 15:18
-
-
Save kaung8khant/490eabd973c86c9d2d1831b459aaa57c to your computer and use it in GitHub Desktop.
Lazy Loading with React, GraphQL and Formik (Phone number input - country code with flag)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { gql } from "apollo-boost"; | |
import { Form,Dropdown } from "semantic-ui-react"; | |
import PhonePrefix from "PhonePrefix"; | |
//use graphql for api call | |
const COUNTRY_QUERY = gql` | |
{ | |
countries { | |
id | |
name | |
nationality | |
phone | |
iso_code_2 | |
} | |
} | |
`; | |
//wrap form with formik for form control | |
const App = (values)=>{ | |
return <Query query={COUNTRY_QUERY}> | |
{({ loading, error, data }) => { | |
let list = data.countries || []; | |
if (loading) { | |
return ( | |
<Form.Field width={4} id="phoneField" className="cityCode"> | |
<Dropdown | |
loading | |
name={"phoneprefix"} | |
fluid | |
className="selectRole boxBorder" | |
size="small" | |
icon="angle down" | |
search | |
selection | |
options={dummyData} | |
/> | |
</Form.Field> | |
); | |
} else { | |
return ( | |
<Form.Field width={4} id="phoneField" className="cityCode"> | |
<PhonePrefix | |
list={list} | |
defaultValue={values.phoneprefix} | |
text={values.phonePrefixText || ""} | |
setFieldValue={setFieldValue} //formik (key,value)=>{} | |
name={"phoneprefix"} | |
/> | |
</Form.Field> | |
); | |
} | |
}} | |
</Query>; | |
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from "react"; | |
import { Dropdown } from "semantic-ui-react"; | |
import _ from "lodash"; | |
import { FlagIcon } from "react-flag-kit"; | |
export default class PhonePrefix extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
list: this.props.list.slice(0, 20), | |
alllist: this.props.list, | |
index: 1, | |
firstScroll: true | |
}; | |
this.myRef = React.createRef(); | |
} | |
componentDidMount() { | |
document.addEventListener("scroll", this.trackScrolling); | |
} | |
componentWillUnmount() { | |
document.removeEventListener("scroll", this.trackScrolling); | |
} | |
checkExist = (list, stateList) => { | |
if (list.length > 0 && stateList.length > 0) { | |
if ( | |
_.find(stateList, item => { | |
return item.id === list[0].id; | |
}) | |
) { | |
return false; | |
} else { | |
return true; | |
} | |
} else { | |
return false; | |
} | |
}; | |
trackScrolling = () => { | |
let { list, alllist, index } = this.state; | |
let intNeed = alllist.length % 10; | |
intNeed = intNeed === 0 ? intNeed : 10 - intNeed; | |
const wrappedElement = this.myRef.current.ref.current.getElementsByClassName( | |
"menu" | |
)[0]; | |
if (this.isBottom(wrappedElement)) { | |
let bottomIndex = index + 1; | |
let start = bottomIndex * 10; | |
let end = bottomIndex * 10 + 10; | |
let newArray = alllist.slice(start, end); | |
if (end <= alllist.length + intNeed) { | |
if (this.checkExist(newArray, list)) { | |
list.push(...newArray); | |
list.splice(0, 10); | |
index++; | |
this.setState({ list: list, index: index, firstScroll: false }); | |
} | |
} | |
} else if (this.isTop(wrappedElement)) { | |
if (!this.state.firstScroll) { | |
let topIndex = index - 2; | |
if (topIndex >= 0) { | |
let start = topIndex * 10; | |
let end = topIndex * 10 + 10; | |
let newArray = alllist.slice(start, end); | |
if (this.checkExist(newArray, list)) { | |
list.unshift(...newArray); | |
end = list.length; | |
start = end - 10; | |
let endIndexForAll = Math.floor(alllist.length / 10); | |
if (intNeed !== 0 && index === endIndexForAll) { | |
start = end - (10 - intNeed); | |
} | |
list.splice(start, end); | |
index--; | |
this.setState({ list: list, index: index }, () => { | |
wrappedElement.scrollTop = 200; | |
}); | |
} | |
} | |
} else { | |
this.setState({ firstScroll: false }); | |
} | |
} | |
}; | |
isBottom(el) { | |
return el.scrollTop > 400; | |
} | |
isTop(el) { | |
return el.scrollTop === 0 && !this.state.firstScroll; | |
} | |
setdata = data => { | |
this.setState({ alllist: data }); | |
}; | |
handleSearch = (e, data) => { | |
let alllist = this.props.list; | |
let result = _.filter(alllist, list => { | |
return ( | |
_.includes(list.name.toLowerCase(), data.searchQuery) || | |
_.includes(list.phone, data.searchQuery) || | |
_.includes(list.iso_code_2.toLowerCase(), data.searchQuery) | |
); | |
}); | |
let list = result.slice(0, 20); | |
this.setState({ | |
alllist: result, | |
list: list, | |
searchQuery: data.searchQuery, | |
index: 1 | |
}); | |
}; | |
render() { | |
let list = []; | |
let countries = this.state.list; | |
if (countries) { | |
countries.map(item => { | |
let noImgList = ["EH", "AQ", "BQ", "MF", "SH"]; | |
if ( | |
!_.find(noImgList, list => { | |
return item.iso_code_2 === list; | |
}) | |
) { | |
let listItem = {}; | |
listItem["key"] = item.id; | |
listItem["text"] = | |
"[" + item.iso_code_2 + "] " + item.name + "( +" + item.phone + ")"; | |
listItem["icon"] = <FlagIcon code={item.iso_code_2} size={20} />; | |
listItem["value"] = item.id; | |
listItem["prefix"] = item.phone; | |
list = [...list, listItem]; | |
return list; | |
} | |
return item; | |
}); | |
} | |
return ( | |
<Dropdown | |
ref={this.myRef} | |
fluid | |
search | |
selection | |
//searchQuery={this.state.searchQuery || ""} | |
onSearchChange={this.handleSearch} | |
name={this.props.name} | |
placeholder="Prefix" | |
options={list} | |
className="phoneFlag selectRole boxBorder" | |
size="small" | |
icon="angle down" | |
loading={this.props.loading} | |
defaultValue={this.props.defaultValue} | |
text={this.props.text || ""} | |
onScroll={this.trackScrolling} | |
onChange={(e, v) => { | |
let selectedItem = _.find(v.options, item => { | |
return item.value === v.value; | |
}); | |
this.props.setFieldValue( | |
"phonePrefixText", | |
"+" + selectedItem.prefix | |
); | |
this.props.setFieldValue(this.props.name, parseInt(v.value)); | |
}} | |
/> | |
); | |
} | |
} |
@hasogolcu Sorry, I don't have access to that repo anymore. There are a few things I would do to improve such as using stack for storing the list and divide the code into diferent chunk.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
hey. can u share this project with code sandbox please? Regards