Reputation: 254
I am developing Currency Converter application using ReactJS. The program is about convert from one currency to another. The application has one form consist of a field with submit button. Moreover it also has initial currency 'USD 10' as a default.
When user type the an abbreviation of currency (e.g.: KRW) in the field and click the submit button. There will be a result below the form that shows the result of the conversion from USD to KRW. If the user want to add more currency, another selection currency will be shown below "KRW" conversion result.
When I am trying to make function to show the result when user submit the abbreviation of currency in the field.
This is the error:
Uncaught (in promise) TypeError: Cannot read property 'rates' of undefined
at Currency.render (App.js:402)
at finishClassComponent (react-dom.development.js:15319)
at updateClassComponent (react-dom.development.js:15274)
at beginWork (react-dom.development.js:16262)
at performUnitOfWork (react-dom.development.js:20279)
at workLoop (react-dom.development.js:20320)
at renderRoot (react-dom.development.js:20400)
at performWorkOnRoot (react-dom.development.js:21357)
at performWork (react-dom.development.js:21267)
at performSyncWork (react-dom.development.js:21241)
at requestWork (react-dom.development.js:21096)
at scheduleWork (react-dom.development.js:20909)
at Object.enqueueSetState (react-dom.development.js:11595)
at App.push../node_modules/react/cjs/react.development.js.Component.setState (react.development.js:336)
at Object.App.addCurrency [as onSubmit] (App.js:34)
at Form.handleSubmit (App.js:204)
And this is my code:
class Currency extends React.Component {
render() {
const p = this.props;
return (
<div className="currency">
{/*<span className="currencyText"><Currency/></span>*/}
<div className="currencyInfo">
<div>{"1 "+p.base + " = " }</div>
<div>{p.data.rates}</div> {/*this is (App.js:402)*/}
</div>
</div>
);
}
}
Instead of that, If I code of Apps.js:402 like this:
<div>{p.data}</div>
and run the app, and check the console in chrome, the result for the line is empty.
The data that I mean is on the picture:
And this is the result of console prop p:
Any solution for this, so that I can retrieve the data rates from the currency?
Upvotes: 0
Views: 6011
Reputation: 4318
Ideally you want some way to manage loading
and no-data
states in your component, depending on what your api returns when there is no data - you might have to manage it differently but that is also a scenario you should cover. Your data seems to be coming from a prop called rates
not data
which is an object with multiple keys.
I am not certain of the structure of your code, but this iteration and checking for loading/no-data states might also be done in the parent component.
class Currency extends React.Component {
render() {
const p = this.props;
const { rates = {} } = p;
const hasData = Object.keys(rates).length > 0;
return !p.loading ? (
<div className="currency">
<div className="currencyInfo">
{ hasData ?
<>
<div>{"1 "+p.base + " = " }</div>
{Object.entries(rates).map(([k, v]) => <div key={k}>{`${k}: ${v}`}</div>)}
</> : <p>No data available</p>
}
</div>
</div>
) : <Loader />
}
}
In a parent component you could do something like:
class ParentComp extends React.Component {
public state = { loading: true, rates: {} };
componentDidMount() {
await this.fetchData(...); // could set loading to false on success
}
render() {
const { rates = {} } = this.state;
const hasData = Object.keys(rates).length > 0;
return (
!this.state.loading ?
hasData ?
Object.entries(rates).map(([k, v]) => <Currency key={k} name={k} value={v} ... />)
: <p>No data available</p>
: <Loader />
);
}
}
Then in your child component:
class Currency extends React.Component {
render() {
return (
<div className='currency'>
<div className='currencyInfo'>
<div>{`${this.props.name}: ${this.props.value}`}</div>
</div>
</div>
);
}
}
Thanks to @Codebling for pointing out the unnecessary addition of v
(value) in the key's
Upvotes: 2
Reputation: 171
I am assuming that your Currency component is a Child and it has a Parent component.
Just initialise a value to your "data" before you pass it to child component.
const Child = props => {
return(
<div>
Child
{props.data.country}
</div>
)
}
const Parent = props => {
// initiate state value to your variables that you are using.
let [data, set_data] = useState(
// this is where your error reside, you did not initiate a value.
{ country: 'abc'}
);
// api call
useEffect(()=>{
axios.get('http://ip-api.com/json/24.48.0.1',{})
.then(function (response) {
console.log(response.data);
set_data(response.data)
})
.catch(function (error) {
console.log(error.config);
});
}, [])
return(
<div>
Parent
<Child data={data}></Child>
</div>
)
}
export default Parent;
Upvotes: 0