I am working on a Mernstack application, in my application I have and Event Model and I want to show a single event when I click the event as a link.
the challenge that I am facing now is how to load a single event API with useEffect. it is working when I use componentDidMount but now I changed my application to use useEffect. with ComponentDidMount I used this.props.match.params.id to get the ID, but now that I am using useEffect, I don't know how to get the ID so that I can display a single event with the details and comments that are associated to it.
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
import AddComingWithModal from "../components/coming-with-modal.component";
import { makeStyles } from "#material-ui/core/styles";
import clsx from "clsx";
import Card from "#material-ui/core/Card";
import CardHeader from "#material-ui/core/CardHeader";
import CardMedia from "#material-ui/core/CardMedia";
import CardContent from "#material-ui/core/CardContent";
import CardActions from "#material-ui/core/CardActions";
import Collapse from "#material-ui/core/Collapse";
import Avatar from "#material-ui/core/Avatar";
import IconButton from "#material-ui/core/IconButton";
import Typography from "#material-ui/core/Typography";
import { red } from "#material-ui/core/colors";
import FavoriteIcon from "#material-ui/icons/Favorite";
import ShareIcon from "#material-ui/icons/Share";
import ExpandMoreIcon from "#material-ui/icons/ExpandMore";
import MoreVertIcon from "#material-ui/icons/MoreVert";
import { useTheme } from "#material-ui/core/styles";
import useMediaQuery from "#material-ui/core/useMediaQuery";
export default function EventAndComments() {
const theme = useTheme();
const [tileData, setTileData] = useState([]);
const useStyles = makeStyles((theme) => ({
root: {
maxWidth: 345,
},
media: {
height: 0,
paddingTop: "56.25%", // 16:9
},
expand: {
transform: "rotate(0deg)",
marginLeft: "auto",
transition: theme.transitions.create("transform", {
duration: theme.transitions.duration.shortest,
}),
},
expandOpen: {
transform: "rotate(180deg)",
},
avatar: {
backgroundColor: red[500],
},
}));
const classes = useStyles();
const [expanded, setExpanded] = React.useState(false);
const handleExpandClick = () => {
setExpanded(!expanded);
};
useEffect((id) => {
axios
.get(
"http://localhost:9000/events/" +
this.props.match.params.id +
"/eventcomments"
)
.then((response) => {
setTileData([...response.data]);
})
.catch(function (error) {
console.log(error);
});
}, []);
return (
<Card className={classes.root}>
<CardHeader
avatar={
<Avatar aria-label="recipe" className={classes.avatar}>
R
</Avatar>
}
action={
<IconButton aria-label="settings">
<MoreVertIcon />
</IconButton>
}
title={tileData.title}
subheader="September 14, 2016"
/>
<CardMedia
className={classes.media}
image="/static/images/cards/paella.jpg"
title="Paella dish"
/>
<CardContent>
<Typography variant="body2" color="textSecondary" component="p">
This impressive paella is a perfect party dish and a fun meal to cook
together with your guests. Add 1 cup of frozen peas along with the
mussels, if you like.
</Typography>
</CardContent>
<CardActions disableSpacing>
<IconButton aria-label="add to favorites">
<FavoriteIcon />
</IconButton>
<IconButton aria-label="share">
<ShareIcon />
</IconButton>
<IconButton
className={clsx(classes.expand, {
[classes.expandOpen]: expanded,
})}
onClick={handleExpandClick}
aria-expanded={expanded}
aria-label="show more"
>
<ExpandMoreIcon />
</IconButton>
</CardActions>
<Collapse in={expanded} timeout="auto" unmountOnExit>
<CardContent>
<Typography paragraph>Method:</Typography>
<Typography paragraph>
Heat 1/2 cup of the broth in a pot until simmering, add saffron and
set aside for 10 minutes.
</Typography>
<Typography paragraph>
Heat oil in a (14- to 16-inch) paella pan or a large, deep skillet
</Typography>
<Typography paragraph>
Add rice and stir very gently to distribute. Top with artichokes and
</Typography>
<Typography>
Set aside off of the heat to let rest for 10 minutes, and then
serve.
</Typography>
</CardContent>
</Collapse>
</Card>
);
}
You can use useParams()
const { id } = useParams()
instead of this.props.match.params.id
Related
So I'm trying to show locale of German in my React app with dayjs but is not working, here is my code, i tried to add locale('de') but that is not doing the job, so i don't know what to try next. I'm trying to learn how to do it, and I don't know if i need to import a locale or it does it take it from 'dayjs'
import React, { Fragment, useContext, useEffect, useState } from 'react';
import dayjs from 'dayjs';
import { getMonth } from '../../utils/calendar/dayjs';
import GlobalContext from '../../context/calendar/GlobalContext';
import styles from '../../styles/Calendar.module.scss';
function SmallCalendar() {
const [currentMonthIdx, setCurrentMonthIdx] = useState(dayjs().month());
const [currentMonth, setCurrentMonth] = useState(getMonth());
useEffect(() => {
setCurrentMonth(getMonth(currentMonthIdx));
}, [currentMonthIdx]);
const { monthIndex, setSmallCalendarMonth, setDaySelected, daySelected } =
useContext(GlobalContext);
useEffect(() => {
setCurrentMonthIdx(monthIndex);
}, [monthIndex]);
function getDayClass(day) {
const format = 'DD-MM-YY';
const nowDay = dayjs().format(format);
const currDay = day.format(format);
const slcDay = daySelected && daySelected.format(format);
if (nowDay === currDay) return styles.day_active;
else if (currDay === slcDay) return styles.day_selected;
else return '';
}
return (
<div className={styles.minicalendar}>
<header className={styles.calendar_header}>
<p
style={{ color: 'var(--color-active)' }}
className='text-gray-500 font-bold'>
{dayjs(new Date(dayjs().locale('de').year(), currentMonthIdx)).format(
'DD MMMM YYYY'
)}
</p>
</header>
<div
className={`grid grid-cols-7 grid-rows-6 ${styles.minicalendar_body}`}>
{currentMonth[0].map((day, i) => (
<span key={i} className='text-sm py-1 text-center'>
{day.format('dd').charAt(0)}
</span>
))}
{currentMonth.map((row, i) => (
<Fragment key={i}>
{row.map((day, inx) => (
<button
key={inx}
onClick={() => {
setSmallCalendarMonth(currentMonthIdx);
setDaySelected(day);
}}
className={`py-1 w-full ${getDayClass(day)}`}>
<span className='text-sm'>{day.format('D')}</span>
</button>
))}
</Fragment>
))}
</div>
</div>
);
}
export default SmallCalendar;
You need to first import the locale at the top of your file.
import 'dayjs/locale/de'
Then you can set the global locale to de
dayjs.locale(‘de’)
import dayjs from 'dayjs';
import <plugin-name> from 'dayjs/plugin/<plugin-name>';
dayjs.extend(<plugin-name>);
This is how you can import any plugin into your react code.
Ex:
import dayjs from "dayjs";
import isSameOrBefore from "dayjs/plugin/isSameOrBefore";
dayjs.extend(isSameOrBefore);
I have a button named "Open dialog" inside Material-UI Select. If I click on it, a dialog will open. I need to write test cases for that button which is inside Select. Can someone explain me how to do it. I am using snapshot testing and this is the code. The test case is failing as "unable to find data-testid openDialog"
main code:
import * as React from 'react';
import Box from '#mui/material/Box';
import InputLabel from '#mui/material/InputLabel';
import MenuItem from '#mui/material/MenuItem';
import FormControl from '#mui/material/FormControl';
import Select, { SelectChangeEvent } from '#mui/material/Select';
import { Button, Dialog, DialogActions, Typography } from '#mui/material';
export default function BasicSelect() {
const [age, setAge] = React.useState('');
const handleChange = (event: SelectChangeEvent) => {
setAge(event.target.value as string);
};
const [openDialog, setOpenDialog] = React.useState(false)
return (
<Box sx={{ minWidth: 120 }}>
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">Age</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={age}
label="Age"
onChange={handleChange}
inputProps={{'data-testid': 'selectForm'}}
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
<div style={{bottom: 0}}>
<Button variant="contained" onClick={() => setOpenDialog(true)} data-testid="openDialog">open dialog</Button>
</div>
</Select>
</FormControl>
<Dialog open={openDialog} maxWidth={'sm'}>
<Typography>hii all</Typography>
<DialogActions>
<Button onClick={() => setOpenDialog(false)} data-testid="cancel">Cancel</Button>
</DialogActions>
</Dialog>
</Box>
);
}
This is my test code:
import { render, fireEvent, screen, cleanup, waitFor } from '#testing-library/react';
and the test case is
it('Open dialog', async() =>
{
const { container } = render(
<ThemeProvider>
<Demo />
</ThemeProvider>
);
const selectForm = screen.getByTestId('selectForm')
fireEvent.click(selectForm);
const openDialog = await waitFor(() => screen.getByTestId('openDialog'));
fireEvent.click(openDialog);
expect(container).toMatchSnapshot();
});
Thank you.
node version : 6.14.11,
Mac OS
I want to be able to use 'response from express' and 'json from body-parser' like this..
nevertheless vscode doesn’t turn on the light 'import code' what i wrote
What i said is first that i think the problem. but i can not be sure :(
enter image description here
import Axios from 'axios';
import { json } from 'body-parser';
import { response } from 'express';
import {React, useEffect} from 'react'
// import { FaCode } from "react-icons/fa";
import {API_URL, API_KEY} from '../../Config';
function LandingPage() {
useEffect(()=>{
const endpoint = `${API_URL}movie/popular?api_key=${API_KEY}&language=en-US&page=1`;
fetch(endpoint)
.then(response => response.json())
.then(response => console.log(response));
// Axios.get(endpoint)
// .then(response => {
// setMovies([...response.results])
// setMainMoveImage(response.results[0])
// })
// endpoint에 받은 값(API)을 fetch가 가져온다? 그렇게보면 될듯
// 그 값이 response에 담긴다. 하지만 response만으로 response을 읽을 수 없기에
// json()을 사용해줌.
},[])
return (
<>
<div style={{ width: '100%', margin: '0'}}>
{/* Main Image */}
<div style={{ width: '85%', margin: '1rem auto'}}>
<h2>Movies by latest</h2>
<hr />
{/* Movie Grid Cards */}
</div>
<div style={{ display: 'flex', justifyContent: 'center'}}>
<button>Load More</button>
</div>
</div>
</>
)
}
export default LandingPage
I've got this problem!
i knew that vscode makes automatically import code!
so if i delete like this,, it would be great
// This is what i will delete!
import { json } from 'body-parser';
import { response } from 'express';
This is the react-native app, runs without errors when the API is not called, the errors only when I run the API created using NodeJs.
I'm getting the error as API call error
Text strings must be rendered within a component.
Below is the error shown in the console where I run the react-native app
Api call error
Error: Text strings must be rendered within a <Text> component.
This error is located at:
in RCTView (at View.js:34)
in View (at ProductContainer.js:125)
in RCTView (at View.js:34)
in View (at ScrollView.js:1124)
in RCTScrollView (at ScrollView.js:1260)
in ScrollView (at ScrollView.js:1286)
in ScrollView (at ProductContainer.js:124)
in RCTView (at View.js:34)
in View (at Container.js:12)
in Container (at connectStyle.js:392)
in Styled(Container) (at ProductContainer.js:104)
in ProductContainer (at SceneView.tsx:122)
in StaticContainer
in StaticContainer (at SceneView.tsx:115)
in EnsureSingleNavigator (at SceneView.tsx:114)
in SceneView (at useDescriptors.tsx:153)
in RCTView (at View.js:34)
in View (at CardContainer.tsx:245)
in RCTView (at View.js:34)
in View (at CardContainer.tsx:244)
in RCTView (at View.js:34)
in View (at CardSheet.tsx:33)
in ForwardRef(CardSheet) (at Card.tsx:573)
in RCTView (at View.js:34)
in View (at createAnimatedComponent.js:165)
in AnimatedComponent (at createAnimatedComponent.js:215)
in ForwardRef(AnimatedComponentWrapper) (at Card.tsx:555)
in PanGestureHandler (at GestureHandlerNative.tsx:13)
at node_modules\react-native\Libraries\LogBox\LogBox.js:148:8 in registerError
at node_modules\react-native\Libraries\LogBox\LogBox.js:59:8 in errorImpl
at node_modules\react-native\Libraries\LogBox\LogBox.js:33:4 in console.error
at node_modules\expo\build\environment\react-native-logs.fx.js:27:4 in error
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:104:6 in reportException
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:171:19 in handleException
at node_modules\react-native\Libraries\Core\ReactFiberErrorDialog.js:43:2 in showErrorDialog
at node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:15258:32 in logCapturedError
at [native code]:null in dispatchAction
at Screens\Products\ProductContainer.js:44:10 in axios.get.then$argument_0
at node_modules\react-native\node_modules\promise\setimmediate\core.js:37:13 in tryCallOne
at node_modules\react-native\node_modules\promise\setimmediate\core.js:123:24 in setImmediate$argument_0at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:130:14 in _callTimer
at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:181:14 in _callImmediatesPass
at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:441:30 in callImmediates
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:387:6 in __callImmediates
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:135:6 in __guard$argument_0
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:364:10 in __guard
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:134:4 in flushedQueue
at [native code]:null in flushedQueue
at [native code]:null in callFunctionReturnFlushedQueue
Here is the screenShot of the error shown in the Mobile app
And Code shown in the error is
if (!hostContext.isInAParentText) {
throw Error("Text strings must be rendered within a <Text> component.");
}
Below provided is the ProductContainer.js Code
import React, { useState, useCallback } from "react";
import {
View,
StyleSheet,
ActivityIndicator,
FlatList,
ScrollView,
Dimensions,
} from "react-native";
import { Container, Header, Icon, Item, Input, Text } from "native-base";
import { useFocusEffect } from "#react-navigation/native";
import axios from "axios";
import ProductList from "./ProductList";
import SearchedProduct from "./SearchedProducts";
import Banner from "../../Shared/Banner";
import CategoryFilter from "./CategoryFilter";
import baseURL from "../../assets/common/baseUrl";
var { height } = Dimensions.get("window");
const ProductContainer = (props) => {
const [products, setProducts] = useState([]);
const [productsFiltered, setProductsFiltered] = useState([]);
const [focus, setFocus] = useState();
const [categories, setCategories] = useState([]);
const [productsCtg, setProductsCtg] = useState([]);
const [active, setActive] = useState();
const [initialState, setInitialState] = useState([]);
const [loading, setLoading] = useState(true);
useFocusEffect(
useCallback(() => {
setFocus(false);
setActive(-1);
// Products
axios
.get(`${baseURL}products`)
.then((res) => {
setProducts(res.data);
setProductsFiltered(res.data);
setProductsCtg(res.data);
setInitialState(res.data);
setLoading(false);
})
.catch((error) => {
console.log("Api call error");
});
// Categories
axios
.get(`${baseURL}categories`)
.then((res) => {
setCategories(res.data);
})
.catch((error) => {
console.log("Api call error");
});
return () => {
setProducts([]);
setProductsFiltered([]);
setFocus();
setCategories([]);
setActive();
setInitialState();
};
}, [])
);
// Product Methods
const searchProduct = (text) => {
setProductsFiltered(
products.filter((i) => i.name.toLowerCase().includes(text.toLowerCase()))
);
};
const openList = () => {
setFocus(true);
};
const onBlur = () => {
setFocus(false);
};
// Categories
const changeCtg = (ctg) => {
{
ctg === "all"
? [setProductsCtg(initialState), setActive(true)]
: [
setProductsCtg(
products.filter((i) => i.category._id === ctg),
setActive(true)
),
];
}
};
return (
<>
{loading == false ? (
<Container>
<Header searchBar rounded>
<Item>
<Icon name="ios-search" />
<Input
placeholder="Search"
onFocus={openList}
onChangeText={(text) => searchProduct(text)}
/>
{focus == true ? (
<Icon onPress={onBlur} name="ios-close" />
) : null}
</Item>
</Header>
{focus == true ? (
<SearchedProduct
navigation={props.navigation}
productsFiltered={productsFiltered}
/>
) : (
<ScrollView>
<View>
for the banner of the home page
<View>
<Banner />
</View>
<View>
<CategoryFilter
categories={categories}
categoryFilter={changeCtg}
productsCtg={productsCtg}
active={active}
setActive={setActive}
/>
</View>
{productsCtg.length > 0 ? (
<View style={styles.listContainer}>
{productsCtg.map((item) => {
return (
<ProductList
navigation={props.navigation}
key={item.name}
item={item}
/>
);
})}
</View>
) : (
<View style={[styles.center, { height: height / 2 }]}>
<Text>No products found</Text>
</View>
)}
</View>
</ScrollView>
)}
</Container>
) : (
// Loading
<Container style={[styles.center, { backgroundColor: "#f2f2f2" }]}>
<ActivityIndicator size="large" color="red" />
</Container>
)}
</>
);
};
const styles = StyleSheet.create({
container: {
flexWrap: "wrap",
backgroundColor: "gainsboro",
},
listContainer: {
height: height,
flex: 1,
flexDirection: "row",
alignItems: "flex-start",
flexWrap: "wrap",
backgroundColor: "gainsboro",
},
center: {
justifyContent: "center",
alignItems: "center",
},
});
export default ProductContainer;
I solve this error with change my IDE.
When I migrate from VS Code to sublime text or notepad++ or android studio, this error solved.
I am asking because the examples I've seen are all in es6 classes.
And: I refactored my es6 class to a functional component. Now no rows appear any more. And no error either. Seems like the row renderer simply renders no rows any more.
Yes, you can use function component with react-virtualized
Does it perform as well as class component? I have no idea, tell me in comment ;)
Example:
import React from 'react'
import {Grid, Typography} from '#material-ui/core'
import PackageItem from './PackageItem'
import {PackagesByCategory} from '../functions/src/types'
import {makeStyles} from '#material-ui/core/styles'
import {WindowScroller, AutoSizer, List, ListRowRenderer, CellMeasurer, CellMeasurerCache} from 'react-virtualized'
const useStyles = makeStyles(theme => ({
container: {
minHeight: "80vh",
width: "100%"
},
title: {
marginTop: 64,
},
}))
const cache = new CellMeasurerCache({
defaultHeight: 60,
fixedWidth: true
});
const PackageCategoriesList = ({packagesByCategories}: PackageCategoriesList) => {
const classes = useStyles()
if(!packagesByCategories) {
return <></>
}
const rowRender: ListRowRenderer = ({index, key, style, parent}) => {
const packageByCategory = packagesByCategories[index]
return <CellMeasurer
cache={cache}
columnIndex={0}
key={key}
overscanRowCount={10}
parent={parent}
rowIndex={index}
>
<Grid item key={key} style={style}>
<Typography variant="h1" className={classes.title}>
{packageByCategory.category.name}
</Typography>
</Grid>
</CellMeasurer>
}
return <div className={classes.container}>
<WindowScroller
scrollElement={window}>
{({height, isScrolling, registerChild, onChildScroll, scrollTop}) => (
<div className={classes.list}>
{console.log("re der list" , height, isScrolling, scrollTop)}
<AutoSizer disableHeight>
{({width}) => (
<div ref={registerChild}>
<List
autoHeight
height={height}
isScrolling={isScrolling}
onScroll={onChildScroll}
overscanRowCount={2}
rowCount={packagesByCategories.length}
rowHeight={cache.rowHeight}
rowRenderer={rowRender}
scrollTop={scrollTop}
width={width}
/>
</div>
)}
</AutoSizer>
</div>
)}
</WindowScroller>
</div>
}
export default PackageCategoriesList