Hi i'm trying to get some data from "currency API" (https://exchangeratesapi.io/)
and this is code below
App.js
import React, { useEffect, useState, Fragment } from "react";
import Header from "./Header";
import Table from "./dashboard/Table";
import { getLatest } from "../actions/currencyAction";
import { useDispatch, useSelector } from "react-redux";
function App() {
const latest = useSelector(state => state.latest);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getLatest());
}, []);
return (
<Fragment>
<Header />
{console.log(latest.rates)}
</Fragment>
);
}
export default App;
currencyAction.js
import { GET_LATEST } from "../actionType";
import axios from "axios";
export function getLatest() {
return dispatch => {
return axios.get("https://api.exchangeratesapi.io/latest").then(res => {
dispatch({ type: GET_LATEST, payload: res.data });
});
};
}
I succesfully got the data from api
<Fragment>
<Header />
{console.log(latest.rates)}
</Fragment>
{CAD: 1.4372, HKD: 8.4324, ISK: 139.3, PHP: 55.248, DKK: 7.4699, …}
CAD: 1.4372
HKD: 8.4324
ISK: 139.3
PHP: 55.248
DKK: 7.4699
HUF: 337.61
CZK: 25.186
AUD: 1.6384
RON: 4.8063
SEK: 10.5833
IDR: 15098.95
INR: 77.8265
BRL: 4.7474
RUB: 70.6675
HRK: 7.465
JPY: 120.52
THB: 34.336
CHF: 1.06
SGD: 1.5164
PLN: 4.2989
BGN: 1.9558
TRY: 6.6599
CNY: 7.6102
NOK: 10.1328
NZD: 1.7095
ZAR: 16.3592
but when I'm trying acces each currency, Everthing collapse..
<Fragment>
<Header />
{console.log(latest.rates.CAD)}
</Fragment>
TypeError: Cannot read property 'CAD' of undefined
App
C:/Users/82102/cb/src/components/App.js:17
14 |
15 | return (
16 | <Fragment>
> 17 | <Header />
| ^ 18 | {console.log(latest.rates.CAD)}
19 | </Fragment>
20 | );
I struggled for whole day long but I just can't figure out why it's happening..
please share your knowledge.. thank you
You're trying to access a property on rates before it has been loaded from the API.
The easy solution is to check its existence first:
Make sure rates is truthy (since typeof null === 'object' is also true),
Check type to see if its an object,
Then access the property.
{latest.rates && typeof latest.rates === 'object' && console.log(latest.rates.CAD)}
Because you use console.log in return causes an error.
You should do the following:
import React, { useEffect, useState, Fragment } from "react";
import Header from "./Header";
import Table from "./dashboard/Table";
import { getLatest } from "../actions/currencyAction";
import { useDispatch, useSelector } from "react-redux";
function App() {
const latest = useSelector(state => state.latest);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getLatest());
}, []);
// add here
console.log(latest.rates)
return (
<Fragment>
<Header />
// remove below line
// {console.log(latest.rates)}
</Fragment>
);
}
export default App;
Related
i want to use query inside child object of Category but im gettin this error.
Unhandled Runtime Error Error:
QueryClientProvider to set one No QueryClient set, use QueryClientProvider to set one
pages/category/[pid].js
15 | heading: pid,
16 | };
> 17 | const { data, isLoading } = useQuery(["movieImage"], get);
| ^
18 | if (isLoading) {
19 | return <div>Loading...</div>;
20 | }
index.js
import Banner from '../components/Banner';
import Category from '../components/Category';
import LiveAuction from '../components/LiveAuction';
import TopCollectors from '../components/TopCollectors';
import TrendingNow from '../components/TrendingNow';
import { ReactQueryDevtools } from "react-query/devtools";
import {
QueryClient,
QueryClientProvider,
} from "react-query";
import { Fragment } from 'react';
const queryClient = new QueryClient();
const Home = () => {
return (
<Fragment>
{" "}
<QueryClientProvider client={queryClient} contextSharing={true}>
<Banner />
<Category />
<LiveAuction />
<TopCollectors />
<TrendingNow />
<ReactQueryDevtools initialIsOpen={true} />
</QueryClientProvider>
</Fragment>
);
}
export default Home
some part of pages/category/[pid].js
const { pid } = router.query;
const { data, isLoading } = useQuery(["movieImage"], getGenres);
if (isLoading) {
return <div>Loading...</div>;
}
tried to change ReactQueryDevtools position
added Fragment
added contextSharing={true} to QueryClientProvider
I'm trying to test component that is wrapped with other component, the parent component has conditional rendering, for explanation:
import React, { FunctionComponent } from 'react'
import { getPermissions, ROLES, PERMISSIONS } from '~/constants/permissions'
import usePermission from '~/hooks/usePermission'
export interface UsePermissionParams {
as: ROLES;
children?: React.ReactNode;
permissions: PERMISSIONS[];
}
// This Component is used to check if the user has the permission to access Specific Component or part of the UI
const CanAccess: FunctionComponent<UsePermissionParams> = ({
as,
children,
permissions,
}) => {
const hasPermission = usePermission({ permissions })
if (as === ROLES.VENDOR) {
const hasAllPermissions = permissions?.every((permission) =>
getPermissions.vendor.includes(permission)
)
if (hasPermission && hasAllPermissions) {
return <>{children}</>
}
} else if (as === ROLES.ADMIN) {
const hasAllPermissions = permissions?.every((permission) =>
getPermissions.admin.includes(permission)
)
if (hasPermission && hasAllPermissions) {
return <>{children}</>
}
}
return <></>
}
export default CanAccess
this is the parent component that wrap the component that I need to test.
and this is the component that I want to test:
import React, { useContext, useState } from 'react'
import { CircularProgress } from '#mui/material'
import { useSelector } from 'react-redux'
import CanAccess from '~/components/CanAccess'
import CreateBox from '~/components/CreateBox'
import { ROLES, PERMISSIONS } from '~/constants/permissions'
import CardHolder from '~/modules/finance/Components/SponsoredProductsTab/Components/CardHolder'
import TopUpModal from '~/modules/finance/Components/TopUpModal'
import { FinanceContext } from '~/modules/finance/FinanceContext'
import * as styles from '~/modules/finance/styles'
import { State } from '~/store'
import { User } from '~/store/user/types'
import { i18n } from '~/translations/i18n'
import { currencySign } from '~/utils/getCurrencySign'
import { ls } from '~/utils/localStorage'
import { separator } from '~/utils/numberSeperator'
const AccountBalance = () => {
const { list, loading } = useContext<any>(FinanceContext)
const [showTopUpModal, setShowTopUpModal] = useState<boolean>(false)
const userRepresentation = useSelector<State, User | null>(
(state) => state.user.data
)
const targetSelected = ls.get('target_code')
const handleOpenTopUpModal = () => {
setShowTopUpModal(true)
}
const onClose = () => {
setShowTopUpModal(false)
}
const renderCreateTopUP = () => (
<CanAccess as={ROLES.VENDOR} permissions={[PERMISSIONS.FO_TOPUP_ACCESS]}>
<CreateBox
label="Top Up"
maxWidth="fit-content"
handleCreateCampaign={handleOpenTopUpModal}
/>
</CanAccess>
)
return (
<>
{showTopUpModal && (
<TopUpModal
onClose={onClose}
advertiserId={
userRepresentation == null
? 0
: userRepresentation?.advertiserId || 0
}
target={targetSelected}
open
/>
)}
<CardHolder
cardHeader="Your account balance:"
cardContent={`${currencySign() || ''} ${
separator(list?.balance) || '0'
}`}
CardBottom={renderCreateTopUP()}
/>
</>
)
}
export default AccountBalance
and this is the test file:
import AccountBalance from '.'
import { render, screen } from '~/test-utils'
describe('AccountBalance', () => {
it('should render the top up button', async () => {
render(<AccountBalance />)
const topUpBtn = await screen.findByText('Top up')
expect(topUpBtn).toBeInTheDocument()
})
})
and I have this error:
<body>
<div>
<div
class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation1 css-s9smhs-MuiPaper-root"
>
<div>
<p
class="MuiTypography-root MuiTypography-body1 css-1tvvmmg-MuiTypography-root"
>
Your account balance:
</p>
<p
class="MuiTypography-root MuiTypography-body1 css-1hd1hip-MuiTypography-root"
>
0
</p>
<div
class="css-0"
/>
</div>
</div>
</div>
</body>
5 | it('should render the top up button', async () => {
6 | render(<AccountBalance />)
> 7 | const topUpBtn = await screen.findByText('Top up')
| ^
8 | expect(topUpBtn).toBeInTheDocument()
9 | })
10 | })
the problem is: any component that is wrapped with the component CanAccess is not rendering and I have null
so what is the problem
I recently decided to learn about state management with easy-peasy, and followed along the basic tutorials, but i can't seem to access the state.
Here is the App component :-
import model from './model';
import Todo from './components/Todo.tsx';
import { StoreProvider, createStore } from 'easy-peasy';
const store = createStore(model);
function App() {
return (
<StoreProvider store={store}>
<div className="App">
<Todo />
</div>
</StoreProvider>
);
}
export default App;
Here is the model file 'model.js'
export default {
todos: [
{
id: 1
},
{
id: 2
},
{
id: 3
}
]
};
And this is the Todo file:-
import React from 'react';
import {useStoreState } from 'easy-peasy';
const Todo = () => {
//The line below does not work for me, when i do 'state.todos' i get an error that todos does not exist on type
const todos = useStoreState(state=>state.todos);
return (
<div>
</div>
);
}
export default Todo;
Try removing the .todos so that
const todos = useStoreState(state=>state.todos);
turns into:
const todos = useStoreState(state=>state);
import React from 'react'
import { useStoreState } from 'easy-peasy';
import Feed from './Feed'
const Home = ({isLoading,fetchError}) => {
const { searchResults} = useStoreState((state)=>state.searchResults)
return (
{isLoading && Loading Posts ...};
{fetchError && <p className='statusMsg' style={{ color: "red" }}>{ fetchError }};
{!isLoading && !fetchError && (searchResults.length ? : No posts to display)}
)
}
export default Home;
I trying to use React context to manage state in my project, but I cannot seem to figure out why it's returning undefined. I copied the example from another project I was working on, and it seems as if everything should be working properly. I just can't seem to pin down why it is not.
Here is where I am creating the context.
import React, { useState } from "react";
const initialTodos = [
{
id: 1,
title: "Setup development environment",
completed: true,
},
{
id: 2,
title: "Develop website and add content",
completed: false,
},
{
id: 3,
title: "Deploy to live server",
completed: false,
},
];
export const TodoContext = React.createContext({
todos: initialTodos,
onChange: () => {},
});
const TodoContextProvider = (props) => {
const [todos, setTodos] = useState(initialTodos);
const handleChange = () => {
console.log("clicked");
};
return (
<TodoContext.Provider value={{ todos: todos, onChange: handleChange }}>
{props.children}
</TodoContext.Provider>
);
};
export default TodoContextProvider;
Here is where I am wrapping the app.
import React from "react";
import ReactDOM from "react-dom";
import TodoContainer from "./components/TodoContainer";
import TodoContextProvider from "./context/TodoContext";
ReactDOM.render(
<TodoContextProvider>
<TodoContainer />
</TodoContextProvider>,
document.getElementById("root")
);
Here is my TodoContainer.
import React, { useContext } from "react";
import TodosList from "./TodosList";
import Header from "./Header";
import TodoContext from "../context/TodoContext";
const TodoContainer = (props) => {
const todoContext = useContext(TodoContext);
console.log("todoContext", todoContext);
return (
<div>
<Header />
<TodosList />
</div>
);
};
export default TodoContainer;
And here is where I am attempting to use the context.
import React, { useContext } from "react";
import TodoItem from "./TodoItem";
import TodoContext from "../context/TodoContext";
const TodosList = (props) => {
const todoContext = useContext(TodoContext);
console.log(todoContext);
return (
<div>
{todoContext.todos.map((todo) => (
<TodoItem key={todo.id} todo={todo.title} />
))}
</div>
);
};
export default TodosList;
Finally, here is the error I receive.
TypeError: Cannot read property 'todos' of undefined
TodosList
C:/Users/Stacey/repos/simple-todo-app/src/components/TodosList.js:11
8 | console.log(todoContext);
9 |
10 | return (
> 11 | <div>
| ^ 12 | {todoContext.todos.map((todo) => (
13 | <TodoItem key={todo.id} todo={todo.title} />
14 | ))}
You are importing the TodoContext as a default import but it must be a named import.
change in the TodosList.js:
import TodoContext from "../context/TodoContext";
to:
import { TodoContext } from "../context/TodoContext";
and it will work
I am trying to write a test for a React functional component that uses Redux and Hooks.
I am using Jest with Enzyme for testing.
For Reference:
This is the functional component being tested:
import React from 'react';
import {useDispatch, useSelector} from "react-redux";
import * as actions from '../../actions/actions';
import { Button, Icon } from "#material-ui/core";
export const EditBatchHeaderComponent = (props) => {
const dispatch = useDispatch();
const { selectedBatch } = props;
const { batchName } = selectedBatch;
return (
<div className="edit-header-container">
<Button disableRipple onClick={() => {dispatch(actions.unSelectBatch())} }>
<Icon>arrow_back</Icon>
</Button>
<span>Edit Batch</span>
<span>{batchName}</span>
</div>
);
};
This is component's container:
import React from 'react';
import { BatchHeaderComponent } from './BatchHeaderComponent';
import { BatchTableComponent } from './BatchTableComponent';
import { EditBatchComponent } from './EditBatchComponent';
import {useSelector} from "react-redux";
import {EditBatchHeaderComponent} from "./EditBatchHeaderComponent";
export const BatchManagementComponent = () => {
const { selectedBatch } = useSelector(state => state.batchManagementReducer);
if (selectedBatch.length) {
return (
<div className="component-container">
<EditBatchHeaderComponent selectedBatch={selectedBatch} />
<EditBatchComponent selectedBatch={selectedBatch} />
</div>
);
}
return (
<div className="component-container">
<BatchHeaderComponent />
<BatchTableComponent />
</div>
);
};
This is the default state of the reducer:
{
sorting: {
order: '',
orderBy: ''
},
searchBy: 'batchName',
searchText: '',
filterByStatus: '--',
filterByType: '--',
waiting: false,
batchData: [],
selectedBatch: {
batchName: '',
},
}
This is the test file that is failing to recognize the props:
import React from 'react';
import { EditBatchHeaderComponent } from '../../../components/batchManagement/EditBatchHeaderComponent';
import configureStore from '../../../store';
import {Provider} from "react-redux";
import Enzyme, { mount } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import {Button} from "#material-ui/core";
Enzyme.configure({ adapter: new Adapter() });
describe('EditBatchHeaderComponent', () => {
it('mounts to the DOM successfully', () => {
const wrapper = mount(<Provider store={configureStore()}>
<EditBatchHeaderComponent />
</Provider>);
expect(wrapper.find(EditBatchHeaderComponent)).toBeDefined();
});
it('deselects the account and closes when the back button is clicked', () => {
const props = {selectedBatch: {batchName: 'INFORM'}, dispatch: jest.fn()};
const obj = {};
const wrapper = mount(
<Provider store={configureStore()}>
<EditBatchHeaderComponent {...props} />
</Provider>
);
console.log(wrapper.find(EditBatchHeaderComponent).props());
wrapper.find(Button).first().simulate('click');
expect(wrapper.find(EditBatchHeaderComponent)).toEqual(obj);
});
});
This is the error text provided by the test suite:
FAIL src/spec/components/batchManagement/EditBatchHeaderComponent.test.js (7.182s)
● EditBatchHeaderComponent › mounts to the DOM successfully
TypeError: Cannot read property 'batchName' of undefined
8 | const dispatch = useDispatch();
9 | const { selectedBatch } = props;
> 10 | const { batchName } = selectedBatch;
| ^
11 | return (
12 | <div className="edit-header-container">
13 | <Button disableRipple onClick={() => {dispatch(actions.unSelectBatch())} }>
I have run a nearly identical test on a similar component that runs and covers the code appropriately.
I can't seem to figure out why the props aren't being recognized.
Any assistance would be greatly appreciated, thanks.