Problems with React and useRoutes - javascript

I am trying to use React and useRoutes, but I get an error and nothing is displayed. I can't figure out where the problem is, can you help me? Thank you very much
This is the error
routes.js:12 Uncaught TypeError: Cannot read properties of undefined (reading 'createElement')
at routes.js:12:17
..
These are my files
App.jsx contains the import of BrowserRouter
import Index from './Index.jsx';
import { BrowserRouter as Router, Link } from "react-router-dom";
import { Menu } from './Menu.jsx';
export const App = () => (
<div>
<Router>
<Menu />
<Index />
</Router>
</div>
);
Index.jsx containing the useRoutes
import { useRoutes } from "react-router-dom";
import { routes } from "./routes";
export const Component = () => {
let element = useRoutes(routes);
return element;
};
export default Component;
router.js where all routes will be declared
import { React } from "react";
import { Home } from './Home.jsx';
import { ErrorPage } from './ErrorPage.jsx';
export const routes = [
{
path:'/',
element:<Home />
},
{
path:'*',
element:<ErrorPage />
}
];
Menu.jsx containing the site menu and consequently the Links
import React, { useState } from 'react';
import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom";
import { pages } from '../../data/pages';
export const MenuTop = () => {
const [myPages, setMyPages] = useState(pages);
const [pageToDisplay, setPageToDisplay] = useState("/");
const displayPage = (page) => {
setPageToDisplay(page.url);
}
return (
<Router>
<div className="ui menu">
{myPages.map((el) => {
const { id, name, url } = el;
return (
<Link to={url} key={id} className={`item ${pageToDisplay == url ? "active" : ""}`} onClick={() => displayPage({url})}>{name}</Link>
);
})}
</div>
</Router>
);
}

The issue is that you're importing the wrong React, using a named export instead of a default one. Here is the error, in the router.js/routes.js:
On the first line, import { React } from 'react'
import { React } from "react";
import { Home } from './Home.jsx';
import { ErrorPage } from './ErrorPage.jsx';
export const routes = [
{
path:'/',
element:<Home />
},
{
path:'*',
element:<ErrorPage />
}
];
Change it to a default export:
import React from "react";
import { Home } from './Home.jsx';
import { ErrorPage } from './ErrorPage.jsx';
export const routes = [
{
path:'/',
element:<Home />
},
{
path:'*',
element:<ErrorPage />
}
];
This should fix the issue.

Related

Uncaught TypeError: Cannot read properties of undefined (reading 'params') while using axios and react-router-dom

It's the HomePage component of ReactJS
import React from 'react';
import axios from 'axios';
import { useState, useEffect } from 'react';
import { useNavigate,useParams } from 'react-router-dom';
import { Main } from '../components/Main';
import { Controls } from '../components/Controls';
import { ALL_COUNTRIES } from '../config';
import { List } from '../components/List';
import { Card } from '../components/Card';
import { Details } from './Details';
export const HomePage = () => {
const [countries,setCountries] = useState([]);
const navigate = useNavigate();
useEffect(() => {
axios.get(ALL_COUNTRIES).then(({data})=>setCountries(data))
},[]);
return (
<>
<Controls/>
<List>
{
countries.map((c) => {
const countryInfo = {
img: c.flags.png,
name: c.name,
info: [
{
title:'Population',
description:c.population.toLocaleString(),
},
{
title:'Region',
description:c.region,
},
{
title:'Flag',
description:c.capital,
},
],
};
return (
<Card
key={c.name}
onClick={(e) => {
navigate('/country/${c.name}');
}}
{...countryInfo}
/>
)
})
}
</List>
</>
);
};
It's second components Details
import React from 'react';
import { useParams } from 'react-router-dom';
export const Details = ({match,params}) => {
const { name } = useParams();
return (
<div>
Details {match.params.name}
</div>
);
};
config.js
const BASE_URL = 'https://restcountries.com/v2/';
export const ALL_COUNTRIES=BASE_URL+"all?fields=name,flags,population,capital,region";
export const searchByContry=(name)=>BASE_URL+'name/'+name;
export const filterByCode=(code)=>BASE_URL+'alpha?code'+code.join('');
APP.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import { Route,Routes,Router,useParams} from 'react-router-dom';
import {useState, useEffect} from 'react';
import './App.css';
import styled from 'styled-components';
import Header from './components/Header';
import { Main } from './components/Main';
import {NotFound} from './pages/NotFound';
import { HomePage } from './pages/HomePage';
import { Details } from './pages/Details';
function App() {
return (
<>
<Header/>
<Main>
<Routes>
<Route path="/" element={<HomePage/>}/>
<Route path="country/:name" element={<Details/>}/>
<Route path="*" element={<NotFound/>}/>
</Routes>
</Main>
</>
);
}
export default App;
HomePage itself looks like this
but when I click on flag/card it sends me on second page as expected but gives me this error
[2]:https://i.stack.imgur.com/39HEw.png
Also, I'm using react-router-domV6 and Axios
and this API https://restcountries.com/v2/all
also both Components are in
APP.js
Details is trying to read params from an undefined object, props.match in this case.
<Route path="country/:name" element={<Details />} /> // <-- no props passed!
...
import React from 'react';
import { useParams } from 'react-router-dom';
export const Details = ({ match, params }) => { // <-- match undefined
const { name } = useParams();
return (
<div>
Details {match.params.name} // <-- Oops, can't read params of undefined
</div>
);
};
Remove the props and access the values returned from the useParams hook.
import React from 'react';
import { useParams } from 'react-router-dom';
export const Details = () => {
const { name } = useParams();
return (
<div>
Details {name}
</div>
);
};
The target path is also malformed. The code navigate('/country/${c.name}') is navigating to the string literal "/country/${c.name}", which is likely not what you meant to do. Fix this to use a string template literal instead to inject the c.name value into the target path.
navigate(`/country/${c.name}`) // note the backticks instead of single quotes
I oftentimes find it useful/helpful to use the generatePath utility function to create path values.
Example:
import { generatePath, useNavigate } from 'react-router-dom';
...
const path = generatePath("/country/:name", { name: c.name });
navigate(path);

React context, I get an error when I refresh the page

What I'm trying to do is to call my service on the main page and then assign context to the response and print it in another component. I can print but when I refresh the page I get an error.
home.js
import React, { useContext, useEffect } from 'react';
import { PolicyContext } from 'contexts/PolicyContext';
import { PolicyService } from 'services/PolicyService';
const Home = () => {
const { policyData, setPolicyData } = useContext(PolicyContext);
const activiesPolicyExampleReq = {
nationalId: '59104492600',
};
useEffect(() => {
PolicyService.getActivePolicies(activiesPolicyExampleReq).subscribe(
(response) => {
setPolicyData(response);
}
);
}, []);
}
PolicyContext.js
import React, { createContext, useMemo, useState } from 'react';
export const PolicyContext = createContext(undefined);
const PolicyContextProvider = (props) => {
const [policyData, setPolicyData] = useState();
console.log('PC');
return (
<PolicyContext.Provider
value={useMemo(() => {
return ({
policyData,
setPolicyData,
});
}, [{ policyData, setPolicyData }])}
>
{props.children}
</PolicyContext.Provider >
);
};
export default PolicyContextProvider;
App.js
import { Route, Router } from 'react-router-dom';
import AppRouter from 'routes/AppRouter';
import { CookiesProvider } from 'react-cookie';
import Header from 'modules/Header';
import Login from 'pages/login/login';
import Onboarding from './pages/onboarding/onboarding';
import PolicyContextProvider from './contexts/PolicyContext';
import React from 'react';
import Theme from 'theme/Theme';
import { history } from './libs/History';
export default function App() {
return (
<Theme>
<CookiesProvider>
<PolicyContextProvider>
<Router history={history}>
<Route exact path={['/onboarding']} component={Onboarding} />
<Route exact path={['/login']} component={Login} />
<Header />
<AppRouter />
</Router>
</PolicyContextProvider>
</CookiesProvider>
</Theme>
);
}
the component i want to print
const { policyData, setPolicyData } = useContext(PolicyContext);
console.log(policyData);
<TabPanel value={value} index={0}>
<PolicyCarousel
policyList={
policyData.activePoliciesMap
? policyData.activePoliciesMap[policiesMapType]
: null
}
policyType={0}
/>
</TabPanel>
error in console:
Cannot read properties of undefined (reading 'activePoliciesMap')

Reuse ReactJS component

I have built a ReactJS component for rendering emoction. Separate component can be built for each emoction, but I want to use one component but pass separate emoction as required.
This is what works so far:
emoction.js
import { faHeart } from "#fortawesome/free-solid-svg-icons";
import { faHeartBroken } from "#fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import React, { useState } from 'react';
const Emoction = () => {
return (
<FontAwesomeIcon icon={faHeart} />
);
};
export default Emoction;
emoction_hb.js
import { faHeart } from "#fortawesome/free-solid-svg-icons";
import { faHeartBroken } from "#fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import React, { useState } from 'react';
const EmoctionHb = () => {
return (
// <input type="text" />
<FontAwesomeIcon icon={faHeartBroken} />
);
};
export default EmoctionHb;
Now, I am bundling these two components as:
expanded_content.js
import Emoction from "../emoctions/emoctions";
import EmoctionHb from "../emoctions/emoctions_hb";
import styled from "#emotion/styled";
import { faHeartBroken } from "#fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import React, { Component } from 'react';
const Merged = styled.div`
display: flex;
flex-direction: row;
justify-content: flex-start;
`;
const expandedContent = () => {
return(
<div>
<Merged>
<Emoction/>
<EmoctionHb/>
</Merged>
</div>
)
};
export default expandedContent;
which when I rendered using App.js
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';
import expandedContent from './components/merged_component/expanded_content'
class App extends React.Component {
render(){
return(
<Router>
<>
<Route path='/ExpandedContent' exact component={expandedContent}/>
</>
</Router>
)
}
}
export default App;
gives me.
What I am trying to do is that instead of creating a component called emoctions_hb.js I want to reuse emoction.js by passing "faHeartBroken" as the value in it.
If emoction.js is called without any value, I want it to use "faHeartBroken" as default value.
Tried following on to create Parent-Child relationship using https://webomnizz.com/change-parent-component-state-from-child-using-hooks-in-react/ but it did not work out for me.
Just pass the icon as a prop and set the default value to faHeartBroken:
const Emoction = ({ faIcon = faHeartBroken }) => {
return (
<FontAwesomeIcon icon={faIcon} />
);
};
It looks like you're importing useState but you're not implementing it anywhere. You could try implementing state in your expanded_content.js file and pass that down to your child component emoction.js, like this:
const ExpandedContent = () => {
const [heart, setHeart] = useState(true)
return(
<div>
<Emoction heart={heart} setHeart={setHeart}/>
</div>
)
};
export default ExpandedContent;
Notice that you will need to change the name of your component. See the docs here https://reactjs.org/docs/hooks-rules.html.
Then, inside of your Emoction component you will have access to heart which is set to true by default and you can also implement some logic to toggle the state using the function setHeart which is passed down from ExpandedContent:
const Emoction = ({heart, setHeart}) => {
const handleHearts = () => {
setHeart(heart => !heart)
}
return (
heart ? <FontAwesomeIcon icon={faHeart} /> : <FontAwesomeIcon icon={faHeartBroken} />
);
};
export default Emoction;
By using a ternary statement to return your component you can decide to show faHeart or faHeartBroken depending on the current state. All you need to do is add the functionality wherever you need it.

Set a cookie in react to true all the time

I want to set a cookie to be on true all the time, not when something is happening or something is clicked.
So there are several tutorials and articles about that. In my case it should be something like: 'mySpecialCookie = true'.
Installing the package: npm install react-cookie
Does it need to be imported in both index.js and App.js?
My index.js looks like this:
import React from 'react';
import ReactDOM from 'react-dom';
import configureStore from './store/configureStore';
import getMiddlewares from './middlewares';
import App from './containers/App';
import * as serviceWorker from './serviceWorker';
const storeConfig = configureStore(getMiddlewares());
ReactDOM.render(
<storeConfig.Provider store={storeConfig.store}>
<App />
</storeConfig.Provider>,
document.getElementById('root')
);
serviceWorker.unregister();
So I assume that inside ReactDOM it should be changed to this?
import { CookiesProvider } from "react-cookie";
...
ReactDOM.render(
<storeConfig.Provider store={storeConfig.store}>
<CookiesProvider>
<App />
</CookiesProvider>
</storeConfig.Provider>,
document.getElementById('root')
);
And in App.js I added it using useCookies hooks but don't know where to use it:
import React, { useEffect } from 'react';
import { useCookies } from 'react-cookie'; //// <--- added it here
import { IntlProvider } from 'react-intl';
import { useSelector, shallowEqual, useDispatch } from 'react-redux';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Main from './Main';
import OrderDetails from './OrderDetails';
import { fetchDictionary } from '../actions/dictionary';
import { getLanguageCode } from '../utils';
import { HOME_PAGE, ORDER_DETAILS } from '../constants/routes';
const App = () => {
const dictionary = useSelector((state) => state.dictionary, shallowEqual);
const routes = [
{ path: HOME_PAGE, component: Main },
{ path: `${ORDER_DETAILS}/:id`, component: OrderDetails }
];
const dispatch = useDispatch();
const [mySpecialCookie, setMySpecialCookie] = useCookies(true); //// <--- added it here
useEffect(() => {
dispatch(fetchDictionary(getLanguageCode()));
}, [dispatch]);
return (
<IntlProvider
key={dictionary.locale}
locale={dictionary.locale}
messages={dictionary.messages}>
<Router>
{routes.map((route, index) => (
<Route
key={index}
path={route.path}
exact
component={route.component}
/>
))}
</Router>
</IntlProvider>
);
};
export default App;
Any suggestions?
I have found a much shorter way to do it using js-cookie.
In the App.js file:
...
import Cookies from 'js-cookie';
...
const App = () => {
...
Cookies.set('mySpecialCookie', true);
...
}

callback render loses router context for child react-router & redux

I've been developing an idea but am getting stuck on something unusual (my brain hurts on react-router).
I am trying to dynamically render a list of items using .map from a returned object (of multiple similar objects) and appending them to the render(){return(<div />)}.
I just dont know another way than call a function then .map the result for this callback.
I think that the way I'm doing this means the rendered items lose context. The react-router <Link /> will function as expected in the normal flow (placed inside the render(){return(<div />)} ) but not when the item is created from outside of the render. I have posted the error below the code.
I have read Many different ways of getting around this using context and location/history and withRouter. Frankly I'm lost.
I would appreciate if someone could look at my example below and guide me in the right direction.
A few notes:
- main focus appears to be in mystuff
- i have many unnecessary imports i know
- stripped down for clarity, i would get lost otherwise
index
import _ from 'lodash';
import React from 'react';
import { render } from 'react-dom';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
import { Provider } from 'react-redux';
import { store, history } from './store';
import Main from './Main';
import { routyr } from './Menu';
// remaining paths in Menu.js (routyr) for menu visibility
const router = (
<Provider store={store}>
<Router history={history}>
<Route path="/" component={Main}>
{routyr}
</Route>
</Router>
</Provider>
)
render (router, document.getElementById('app'));
Main
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as actionCreators from './actionCreators';
import App from './app';
function mapStateToProps(state){
return{
info: state.info,
myProfile: state.myProfile
}
}
function mapDispatchToProps(dispatch){
return { actions: bindActionCreators(actionCreators, dispatch) }
}
const Main = connect(mapStateToProps, mapDispatchToProps)(App);
export default Main;
routyr
import React from 'react';
import { Link } from 'react-router';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
import { Provider } from 'react-redux';
import { store, history } from './store';
//pages
import App from './app';
import Landing from './Landing';
import Me from './mystuff';
import ViewStuff from './viewStuff';
//Routes for index.js
export const routyr = (
<span>
<IndexRoute component={Landing} />
<Route path="/myStuff" component={Me} />
<Route path="/viewStuff" component={ViewStuff} />
</span>
)
//Menu types
//loaded by app.js
export const menuLoggedIn = (
<div className="MainMenu">
<Link to='/' className="buttonA green">Home</Link>
<Link to='myStuff' className="buttonA green">My Stuff</Link>
</div>
);
export const menuLoggedOut = (
<div className="MainMenu">
<Link to='/login' className="buttonA green">Login</Link>
</div>
);
app
import React from 'react';
import _ from 'lodash';
import { Link } from 'react-router';
import auth from './auth';
import Landing from './Landing';
import Header from './Header';
import { menuLoggedIn, menuLoggedOut } from './Menu';
export default class App extends React.Component {
constructor(){
super();
this.state={
auth: auth.loggedIn(),
menu: null
};
}
componentWillMount(){
if (this.state.auth==true) {
this.setState({
menu: menuLoggedIn
})
}else{
this.setState({
menu: menuLoggedOut
});
}
}
render(){
return (
<div>
<Header />
{this.state.menu}<br />
<div id="view">
{React.cloneElement(this.props.children, this.props)}
</div>
</div>
);
}
};
mystuff
import React, { PropTypes } from 'react';
import { render } from 'react-dom';
import { Link } from 'react-router';
import { withRouter } from 'react-router';
import { Provider } from 'react-redux';
import * from './whacks';
export default class Me extends React.Component{
constructor(){
super();
}
componentDidMount() {
function listThem(oio){
oio.map(function(ducks){
render(
<div className="ListItem">
<Link to="/viewStuff"> _BROKEN_ View Stuff</Link>
<div className="listLabel">{ducks.type}</div>
<h3>{ducks.description.title}</h3>
{ducks.description.long}
</div>, document.getElementById('fishes').appendChild(document.createElement('div'))
);
});
}
var some = new Whacks();
some.thing(more, (close, open) => {
if(close){
console.log(close));
} else {
doIt(open);
}
});
}
render(){
return(
<div>
<Link to="viewStuff"> _WORKING_ View Stuff</Link>
<div id="fishes">
</div>
</div>
)
}
}
store
import { createStore, compose } from 'redux';
import { syncHistoryWithStore } from 'react-router-redux';
import { browserHistory } from 'react-router';
import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
/*-------ROOT REDUCER---------*/
/*-------DEFAULT STATES---------*/
/*-------CREATE STORE---------*/
/*-------INTEGRATE HISTORY---------*/
import me from './reducers/obj';
import myProfile from './reducers/myProfile';
const rootReducer = combineReducers(
{
routing: routerReducer,
me,
myProfile
}
);
//TEMP remove harcoded var
const uuidSet = "fa78d964";
export const defaultState = {
uuid: uuidSet,
};
export const store = createStore(rootReducer, defaultState, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
export const history = syncHistoryWithStore(browserHistory, store);
actionCreators
export function me (obj){
return {
type: "ADD_OBJECTLIST",
obj
}
}
export function myProfile (dump){
return {
type: "MY_DATA",
dump
}
}
from package.json
"react-redux": "^5.0.2",
"react-router": "^3.0.2",
"react-router-redux": "^4.0.7",
"redux": "^3.6.0",
error
Uncaught Error: s rendered outside of a router context cannot navigate.
#UG,
I have tried the following in mystuff:
constructor(){
super();
this.state={
oio: {}
};
}
and
some.thing(more, (close, open) => {
if(close){
console.log(close));
} else {
this.setState({
oio: open
});
}
});
and
render(){
let flat = this.state.oio;
flat.map(function(ducks){
return (
<div className="ListItem">
<Link to="/viewStuff">View Stuff</Link>
<div className="listLabel">{ducks.type}</div>
<h3>{ducks.description.title}</h3>
{ducks.description.long}
</div>
)
})
}
and receive
Uncaught TypeError: flat.map is not a function
at Me.render
I am not sure if I get your issue completely. But I think you want to use Link inside render() method of myStuff
You can change that to following :
render(){
return(
<div>
<Link to="viewStuff"> _WORKING_ View Stuff</Link>
<div id="fishes">
{
oio.map(function(ducks){
return (
<div className="ListItem">
<Link to="/viewStuff"> _BROKEN_ View Stuff</Link>
<div className="listLabel">{ducks.type}</div>
<h3>{ducks.description.title}</h3>
{ducks.description.long}
</div>
);
}
</div>
</div>
)
}
As per the comment from James,
You should use react state to maintain oio object.
constructor() {
super();
//init
this.setState({oio : {}});
}
and update the state in async call, when state updates, component can be rerendered.
Huge thanks to UG_ for smacking me in the ear with state.
I have pulled in a component and created each components props from the callback objects.
My Working solution is as follows in mystuff:
constructor(props){
super(props);
this.state={
oio: []
}
}
componentDidMount() {
let listThem = (stuff) => {
let ioi = [];
stuff.forEach(function(dood, index, array) {
let lame = <MyItem plop={dood} key={index} />;
ioi.push(lame);
});
return (
this.setState({
oio: ioi
})
);
}
var some = new Whacks();
some.thing(more, (close, open) => {
if(close){
console.log(close));
} else {
listThem(open);
}
});
}
render(){
return(
<div>
{this.state.oio}
</div>
)
}
Which renders a new copy of the MyItem component with props from each returned object. So now my returned items contain context!

Categories

Resources