Problems with React Router/Hoook - javascript

Update (new changes):
So now I pretty much converted my code to a functional component however it is as if nothing is being returned from the API, or perhaps I am not "mounting" correctly? I get the error " TypeError: Cannot read property 'map' of undefined" meaning nothing is being returned but I'm not sure why. Help?
Old post (I had previously tried to use a hook in a a class component):
I'm pretty brand new to react and recently I have been getting this error from when trying to navigate to a page on click of a card media (using material ui). So I pretty much follow the instruction to push to history the route to the page I want to navigate to via a function and call that function when I click the media card. Below is my code and the error I get. Do you have any idea why I might be having an issue with this?
My updated code
import Card from '#material-ui/core/Card';
import CardMedia from '#material-ui/core/CardMedia';
import Grid from '#material-ui/core/Grid';
import Container from '#material-ui/core/Container';
import {getItems} from "../Network/network_utility";
import {useHistory} from "react-router-dom";
import {makeStyles} from '#material-ui/core/styles';
import React, {useState, useEffect} from "react";
const useStyles = makeStyles(theme => ({
icon: {
marginRight: theme.spacing(2),
},
heroContent: {
padding: theme.spacing(8, 0, 6),
},
cardGrid: {
paddingTop: theme.spacing(6),
paddingBottom: theme.spacing(3),
position: "fixed"
}
}));
export default function Items() {
let history = useHistory();
const classes = useStyles();
const useFeaturedItems = () => {
const [featured_items, setFeaturedItems] = useState([]);
useEffect(() => {
getItems(1).then(response => setFeaturedItems(response["data"]))}, []);
return featured_items;
};
return (
<div>
<Container className={classes.cardGrid} maxWidth="lg">
<Grid container spacing={6}>
{useFeaturedItems().map((card, index) => (
<Grid item key={index} xs={16} sm={4} md={2}>
<Card raised={false} style={{height: "30vh", width: "20vh"}}>
<CardMedia
component="img"
src={card["thumbnail"]}
style={{height: "25vh", width: "20vh"}}
onClick={history.push("/item")}
>
</CardMedia>
<div style={{paddingLeft: "10px", paddingTop: "10px"}}>
<text style={{
whiteSpace: "nowrap",
overflow: "hidden",
display: "block",
textOverflow: "ellipsis"
}}>
{card["title"]}
</text>
</div>
</Card>
</Grid>
))}
</Grid>
</Container>
</div>
);
}

As I can see you are using hook inside a class component. It is not possibile
how use hook
You can’t use Hooks inside a class component, but you can definitely mix classes and function components with Hooks in a single tree. Whether a component is a class or a function that uses Hooks is an implementation detail of that component. In the longer term, we expect Hooks to be the primary way people write React components.
In class component you need to use the HOC withRouter. After that you can access the history through props with this.props.history

Related

Error when using usercentrics (via gtm) and id's in some components

we try to switch from our own implemented CMP to usercentrics. Therefore we integrated usercentrics via gtm on our page. I realized that the element is only shown on our subpages and is not visible on our root page.
After two days of removing and adding components again. I found out that usercentrics was able to load when I removed the id={"process"} from the component. I'm using multiple times the id tag for a smoothscroll plugin on our page. But only the one applied on the process and the one applied on the contact section are the ones that lead to the error below.
After I removed the plugin and nearly all id's beside one, I got the following error:
Uncaught TypeError: Cannot read property 'REACT_APP_SC_ATTR' of undefined
at bundle_legacy.js:1
at bundle_legacy.js:15
We're using a Gatsby Stack with Typescript and gatsby-plugin-smoothscroll for scrolling.
We implemented gtm via a Gatsby Plugin as well: gatsby-plugin-google-tagmanager
import React from "react";
import colors from "../../../../config/GlobalStyles";
import {Container, Grid, makeStyles, Typography} from "#material-ui/core";
// #ts-ignore
import infoGraphic from "../../../../images/root/process/infographic.webp";
import {graphql, useStaticQuery} from "gatsby";
import Markdown from "markdown-to-jsx";
const useStyles = makeStyles((theme) => ({
contentWrapper: {
paddingTop: "50px"
},
container: {
paddingTop: "50px",
backgroundColor: "white",
},
headline: {
fontWeight: 600,
color: colors.main
},
secondHeadline: {
fontFamily: "Mackay",
color: colors.main,
fontWeight: 400,
},
infoGraphicWrapper: {
overflow: "scroll",
[theme.breakpoints.down('sm')]: {
marginTop: "50px",
},
"& img": {
[theme.breakpoints.down('sm')]: {
maxWidth: "200%"
}
}
}
}));
export default function ProcessSection() {
const classes = useStyles();
const data = useStaticQuery(query);
return (
<section>
<Container className={classes.container}>
<Typography variant={"h2"} component={"h2"} className={classes.headline}>
<Markdown>
{data.strapiHome.process.headline}
</Markdown>
</Typography>
<Typography variant={"h2"} component={"h2"} className={classes.secondHeadline}>
<Markdown>
{data.strapiHome.process.secondHeadline}
</Markdown>
</Typography>
<Grid container className={classes.contentWrapper} justify={"space-between"}>
<Grid item xl={4} lg={4} md={4} sm={12} xs={12}>
<Typography component={"div"} variant={"body2"}>
<Markdown>{data.strapiHome.process.text}</Markdown>
</Typography>
</Grid>
<Grid item xl={7} lg={7} md={7} sm={12} xs={12} className={classes.infoGraphicWrapper}>
<img src={infoGraphic} alt={"alt text"} />
</Grid>
</Grid>
</Container>
</section>
);
}
const query = graphql`
query {
strapiHome {
process {
headline
secondHeadline
text
}
}
}
`;
I have no idea where this is coming from and what the env variables mean.
I think your problem is not in the code. To my point of view, it is related to the .env file.
If you are using process.env.REACT_APP_SC_ATTR somewhere, check the .env file to see if REACT_APP_SC_ATTR is defined.
.env file is like a global config. We normally add server url, port, production mode, things like this.
I was able to resolve the issue by removing all id's from my components and add some of them again.
I was not able to understand why this happened.

Warning: encountered two children with the same key, is appearing as an error in my REACT app

I'm in the process of building out a simple react act that display REST data from my localhost URL.
I keep getting this error and I'm not sure why, at first I thought it was the data within the API itself but I think that's not the case for this?
I am not getting any npm start errors, the error appears when I inspect a page with browser tools.
Here is the full error:
index.js:1 Warning: Encountered two children with the same key, `1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
at div
at Grid (http://localhost:4000/static/js/0.chunk.js:1556:35)
at WithStyles(ForwardRef(Grid)) (http://localhost:4000/static/js/0.chunk.js:6385:31)
at main
at Container (http://localhost:4000/static/js/0.chunk.js:1101:23)
at WithStyles(ForwardRef(Container)) (http://localhost:4000/static/js/0.chunk.js:6385:31)
at UserBuckets (http://localhost:4000/static/js/main.chunk.js:363:5)
at LoadingComponent (http://localhost:4000/static/js/main.chunk.js:999:5)
at div
at App (http://localhost:4000/static/js/main.chunk.js:173:89)
at Route (http://localhost:4000/static/js/0.chunk.js:48473:29)
at Switch (http://localhost:4000/static/js/0.chunk.js:48675:29)
at Router (http://localhost:4000/static/js/0.chunk.js:48108:30)
at BrowserRouter (http://localhost:4000/static/js/0.chunk.js:47728:35)
Could someone point out what is causing this error in my code? I haven't been able to solve it myself.
Here is my required code:
App.js
import React, { useEffect, useState } from 'react';
import './App.css';
import UserBuckets from './components/BucketLists';
import LoadingComponent from './components/Loading';
function App() {
const ListLoading = LoadingComponent(UserBuckets);
const [appState, setAppState] = useState({
loading: false,
buckets: null,
});
useEffect(() => {
setAppState({ loading: true });
const apiUrl = `http://127.0.0.1:8000/api/`;
fetch(apiUrl)
.then((data) => data.json())
.then((buckets) => {
setAppState({ loading: false, buckets: buckets });
});
}, [setAppState]);
return (
<div className="App">
<h1>Latest Buckets</h1>
<ListLoading isLoading={appState.loading} buckets={appState.buckets} />
</div>
);
}
export default App;
bucketList.js
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Card from '#material-ui/core/Card';
import CardContent from '#material-ui/core/CardContent';
import CardMedia from '#material-ui/core/CardMedia';
import Grid from '#material-ui/core/Grid';
import Typography from '#material-ui/core/Typography';
import Container from '#material-ui/core/Container';
const useStyles = makeStyles((theme) => ({
cardMedia: {
paddingTop: '56.25%', // 16:9
},
link: {
margin: theme.spacing(1, 1.5),
},
cardHeader: {
backgroundColor:
theme.palette.type === 'light'
? theme.palette.grey[200]
: theme.palette.grey[700],
},
bucketTitle: {
fontSize: '16px',
textAlign: 'left',
},
bucketText: {
display: 'flex',
justifyContent: 'left',
alignItems: 'baseline',
fontSize: '12px',
textAlign: 'left',
marginBottom: theme.spacing(2),
},
}));
const UserBuckets = (props) => {
const { buckets } = props;
const classes = useStyles();
if (!buckets || buckets.length === 0) return <p>Can not find any buckets, sorry</p>;
return (
<React.Fragment>
<Container maxWidth="md" component="main">
<Grid container spacing={5} alignItems="flex-end">
{buckets.map((buckets) => {
return (
// Enterprise card is full width at sm breakpoint
<Grid item key={buckets.owner} xs={12} md={4}>
<Card className={classes.card}>
<CardMedia
className={classes.cardMedia}
image="https://source.unsplash.com/random"
title="Image title"
/>
<CardContent className={classes.cardContent}>
<Typography
gutterBottom
variant="h6"
component="h2"
className={classes.bucketTitle}
>
{buckets.name.substr(0, 50)}...
</Typography>
<div className={classes.bucketText}>
<Typography
component="p"
color="textPrimary"
></Typography>
<Typography variant="p" color="textSecondary">
{buckets.stock_list}...
</Typography>
</div>
</CardContent>
</Card>
</Grid>
);
})}
</Grid>
</Container>
</React.Fragment>
);
};
export default UserBuckets;
Loading.js
import React from 'react';
function LoadingComponent(Component) {
return function LoadingComponent({ isLoading, ...props }) {
if (!isLoading) return <Component {...props} />;
return (
<p style={{ fontSize: '25px' }}>
We are waiting for the data to load!...
</p>
);
};
}
export default LoadingComponent;
Thank in advance...
The error came from this culprit and my mistake not seeing the important of the letter key in item key. This is how I solved my error:
original code
<Grid item key={buckets.owner} xs={12} md={4}>
fixed code
<Grid item key={buckets.id} xs={12} md={4}>

Fixing React Native CheckBox

I have a React Native project. My understanding is that react native doesn't allow you to style checkboxes inherently, so I am using react-native-check-box and looking on expo.
When running I get "Unidentified is not an object (evaluating 'this.state.isChecked')"
I am using the exact suggested code from https://www.npmjs.com/package/react-native-check-box#demo
What is going wrong?
import React, { useState } from 'react';
import { Text, View, Image } from 'react-native';
import CheckBox from 'react-native-check-box';
import defaultStyles from "../../config/styles";
function AuthorizeInput () {
return (
<View style={defaultStyles.authorize}>
<CheckBox
style={{flex: 1, padding: 10}}
onClick={()=>{
this.setState({
isChecked:!this.state.isChecked
})
}}
isChecked={this.state.isChecked}
/>
<Text style={defaultStyles.authText}>I am an authorized representative of this business.</Text>
</View>
);
}
export default AuthorizeInput;
With functional components u can't use this.setState (only with class ones). However you can use useState hook. For example:
import React, { useState } from "react";
import { Text, View, Image } from "react-native";
import CheckBox from "react-native-check-box";
import defaultStyles from "../../config/styles";
function AuthorizeInput() {
// default value is false
const [checked, setChecked] = useState(false);
return (
<View style={defaultStyles.authorize}>
<CheckBox
style={{ flex: 1, padding: 10 }}
onClick={() => setChecked(!checked)}
isChecked={checked}
/>
<Text style={defaultStyles.authText}>
I am an authorized representative of this business.
</Text>
</View>
);
}
export default AuthorizeInput;

React.useContext() keeps returning undefined?

I'm using Next.js and React, using react hooks + context to manage state. However, I've run into this issue, where React.useContext() returns undefined even though I'm passing in my context object (or so I think, anyway). Am I missing something really obvious? What's happening?
I've created the context in a const called CartContext, and then in my provider component, I have created the value object and passed it as a prop to CartContext.Provider (see below, in _app.js). I made sure the context provider was wrapping my components by adding an <h1> element just to make sure.
The problem seems to occur in index.js. I've imported the CartContext from ./_app.js and then passed it as the argument to useContext() which is supposedly what I should do, but it keeps throwing this error:
"TypeError: Cannot destructure property 'firstSample' of 'react__WEBPACK_IMPORTED_MODULE_0___default.a.useContext(...)' as it is undefined"
which from what I have gathered tells me that useContext() is returning undefined.
_app.js (wraps all pages)
import React from 'react'
import '../styles/global.css';
import theme from '../components/customTheme';
import { ThemeProvider } from '#material-ui/core/styles';
const MyApp = props => {
const { Component, pageProps, store } = props
return (
<ContextProvider>
<ThemeProvider theme={theme}>
<Component {...pageProps} />
</ThemeProvider>
</ContextProvider>
)
}
// Context
export const CartContext = React.createContext()
function ContextProvider({ children }) {
const value = {
firstSample: "Test",
exampleFunction: () => {alert("Hello World")},
}
return (
<CartContext.Provider value={value}>
<h1>The provider works</h1>
{children}
</CartContext.Provider>
)
}
export default MyApp;
index.js
import Nav from '../components/nav';
import Footer from '../components/footer';
import Product from '../components/product';
import { makeStyles } from '#material-ui/core/styles';
import CartContext from './_app';
import {
Typography,
Button
} from '#material-ui/core';
const useStyles = makeStyles({
body: {
margin: '13vh 0 3vh',
backgroundColor: ' white',
textAlign: 'left'
},
earnWrapper: {
display: 'block',
textAlign: 'left',
backgroundColor: 'white',
width: 'calc(100% - 4vh)',
margin: '5% 2vh 12%',
borderRadius: '25px',
transition: '0.3s',
boxShadow: '0px 5px 20px #dedede'
},
earnContent: {
padding: '7%',
textAlign: 'left',
display: 'inline-block'
},
earntCaption: {
color: 'grey',
},
earntAmount: {
margin: '0.5vh 0 1.5vh'
},
withdraw: {
width: '130px',
height: '40px'
},
shareInfo: {
margin: '5% 2vh',
textAlign: 'left'
},
products: {
textAlign: 'center ',
width: '100%'
}
});
export default function Home(props) {
const styles = useStyles();
// Grab data from parent context
const { firstSample } = React.useContext(
CartContext
)
return (
<div>
<DefaultHead
title="Oorigin | Home"
/>
<Nav isLoggedIn={true} />
<div className={styles.body}>
<div className={styles.earnWrapper}>
<div className={styles.earnContent}>
<Typography className={styles.earntCaption} variant="caption">You've earned</Typography>
<Typography className={styles.earntAmount} variant="h4">S$18.50</Typography>
<Button className={styles.withdraw} disableElevation variant="contained" color="primary">Withdraw</Button>
</div>
</div>
<div className={styles.shareInfo}>
<Typography><b>Shop, Share, Earn</b></Typography>
<Typography><br/>Shop products you like, share products you love, and earn up to 10% commission on every qualifying sale you refer</Typography>
</div>
<div className={styles.products}>
<Product
imgURL="../TestItem1.svg"
imgAlt="Test Product"
title="Disinfecting Air Purifying Solution"
price={(22.80).toFixed(2)}
link="/products/staticProduct"
/>
<Product
imgURL="../TestItem2.svg"
imgAlt="Test Product"
title="Disinfecting Air Purifying Solution"
price={(22.80).toFixed(2)}
/>
<Product
imgURL="../TestItem3.svg"
imgAlt="Test Product"
title="Disinfecting Air Purifying Solution"
price={(22.80).toFixed(2)}
/>
<Product
imgURL="../TestItem4.svg"
imgAlt="Test Product"
title="Disinfecting Air Purifying Solution"
price={(22.80).toFixed(2)}
/>
</div>
</div>
<Footer/>
<h1>{firstSample}</h1>
</div>
);
}
Ok so it was a really simple mistake, I imported CartContext in index.js as
import cartContex from _app.js, when it should be with curley brackets because it is not the default export. So the corrected (functional) code is simply: import { cartContext } from _app.js
There are some problems with your code, I do not understand why your createContext stays with the component<MyApp />.
Problems:
In the MyApp component you are doingexport default MyApp and export CartContext, I believe this is not possible.
Your createContext is without adefaultValue, maybe that's the reason to return undefined. See the example in the documentation
I believe that by making these changes your code should work, or at least you can evolve with your problem.
It would be easier to help with a codesandbox.
Try to import like this :
import { CartContext } from './_app';

React-redux not picking up state when recursively rendering components

I am facing an issue where a component Question is not correctly receiving data from my react-redux store. When the component is initially rendered, it receives the desired data from the store with no issue. The problem arises when the question becomes a sub-question - when this is the case, the data from the store is not retrieved and is instead undefined, despite it being the same code. The sub-question code can be seen below where it renders a new Question component within the same Question component. This recursively rendered component does not receive the correct state.
The initial render code snippet is as follows, placed in an outside component from Question:
<div style={{ paddingRight: '8px' }}>
{data.Question.map(question => (
<Question question={question} key={question.ID} />
))}
</div>
The Question component is as follows:
import React from 'react';
import Typography from '#material-ui/core/Typography';
import Grid from '#material-ui/core/Grid';
import FlexibleInput from '../Inputs/FlexibleInput';
import {checkConditionals} from '../../dataHelper';
import { connect } from 'react-redux';
const mapStateToProps = (state, ownProps) => {
return {
answers: state.answers,
activeStep: state.stepper
}
}
const mapDispatchToProps = { }
class Question extends React.Component {
getStyle = () => {
if (this.props.subQuestion) return {paddingLeft: '24px', paddingRight: '-12px'}
return {}
}
render() {
const question = this.props.question;
console.log(this.props.activeStep, question.ID, this.props.answers);
return (
<React.Fragment>
{checkConditionals(question, this.props.answers) ? (
<div style={this.getStyle()}>
{/*Grid is used to placed the question and the possible answers on the same line*/}
<Grid container spacing={2}>
<Grid item> {/*Grid item for the question's prompt*/}
<Typography style={{padding: '12px', fontSize: '1rem'}}>
{question.Description}
</Typography>
</Grid>
<Grid item> {/*Grid item for the question's answer options*/}
<FlexibleInput obj={question}/>
</Grid>
</Grid>
{/*Display a question's sub-questions if they exist, mapping each sub question in the array to a new section*/
question.SubQuestion ? (
question.SubQuestion.map(subQuestion => (
<Question question={subQuestion} key={subQuestion.ID} subQuestion={true}/>
))
) : (
<React.Fragment></React.Fragment>
) }
</div>
) : (
<React.Fragment></React.Fragment>
)}
</React.Fragment>
);
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Question);
Question, on its own, does not have access to the store. By using connect you create a new component, and that component has access to the store. You do use connect at the end of the file, and you export the connected component, so as far as the rest of your codebase is concerned everything is fine. But inside this particular file, any references to <Question> are referring to the unconnected component.
Perhaps do this:
class Question extends React.Component {
// ... later, in render
question.SubQuestion.map(subQuestion => (
<ConnectedQuestion question={subQuestion} key={subQuestion.ID} subQuestion={true}/>
))
}
const ConnectedQuestion = connect(
mapStateToProps,
mapDispatchToProps
)(Question);
export default ConnectedQuestion;

Categories