I'm building an e-commerce with React, in which, there is a dropdown menu that has different currencies. The currencies are coming from a GraphQL endpoint that has all the info. When the user choose a currency, it changes the listed prices. That is implemented by a contexts and I consume that context in the currency selector component. All of this works fine, however, when I start the web from the very beginning, nothing shows up as there is no currency saved as a default. I'm trying to save the first currency in the dropdown menu to the local storage and set it to the context but nothing of this worked for me. Please let me know what do you recommend to do that?
I will attach my code below for the currency selector component and the currency context.
CurrencyContext.js
export const CurrencyContext = createContext()
class CurrencyContextProvider extends Component {
state = {selectedCurrency: 'uiu'}
setCurrency = (c)=>{
this.setState({selectedCurrency: c})
}
render() {
return (
<CurrencyContext.Provider value={{...this.state, setCurrency: this.setCurrency}}>
{this.props.children}
</CurrencyContext.Provider>
)
}
}
export default CurrencyContextProvider;
CurrencySelector.js
export class CurrencySelector extends React.Component{
constructor(props) {
super(props)
this.state = { currencies: [] }
}
async componentDidMount(){
let currencies = (await this.getCurrencies()).data.currencies
this.setState({ currencies:currencies } )
}
async getCurrencies(){
return await fetchTheQuery( `query{ currencies }` )
}
render() {
return (
<CurrencyContext.Consumer>
{(currencyContext) => {
const {setCurrency} =currencyContext
return(
<select name="currency-selector"
onChange={event => {
setCurrency(event.target.value)
localStorage.setItem("currency", event.target.value)
}}>
{this.state.currencies.map(
(currency, index) => {
return (
<option value={currency}>
{currency}
</option>
)
}
)}
</select>
)
}}
</CurrencyContext.Consumer>
)
}
}
If I understood you problem correctly , you need to load default value in the select box before the API returns the data. You also want to keep the previous value chose by user as the selected value when the response is recieved by the GraphQL API. Here is what you can do :
In the contextProvider load the default value from localStorage as follows :
function getDefaultValue() {
const currency = localStorage.getItem('currency');
return currency ? currency : 'USD';
}
const defaultVal = getDefaultValue(); //Insert the default value here.
export const CurrencyContext = createContext();
class CurrencyContextProvider extends Component {
constructor(props) {
super(props);
this.state = { selectedCurrency: defaultVal }; // initial value in state
this.setCurrency = this.setCurrency.bind(this);
}
... rest of the code
Now the consumer will receive selectedCurrency with the default value populated from the localStorage.
Now In consumer, you need to check and toggle b/w options :
{currencies.length
? currencies.map((currency, index) => {
return <option value={currency}>{currency}</option>;
})
: // render the default currency from context when currency is not loaded
[selectedCurrency].map((currency, index) => {
return <option value={currency}>{currency}</option>;
})}
Also you need to set the value prop on select with selectedCurrency.
Here is the Working example : Stackblitz Demo
P.S : You should consider moving the entire code to functional components and utilise useContext hook.
Is it possible the function in onChange is not running currently?
Maybe you can isolate the function you pass into onChange to a class function called handleChange.