TypeError: Object(...) is not a function error in useAccordianToggle - javascript

I'm new to react. I'm using react-bootstrap and trying to create an accordion having more than 20 cards in it. Each card header has a right/down pointing caret icon. I want to toggle the icon to point down or point right based on whether the card body is collapsed or not. So, i tried implementing the example from react-bootstrap website Custom Toggle with Expansion Awaremess and I'm getting the above error at the line
const decoratedOnClick = useAccordionToggle(
eventKey,
() => callback && callback(eventKey),
);
The complete code is below.
import React, {useContext} from 'react';
import Accordion from 'react-bootstrap/Accordion';
import useAccordionToggle from 'react-bootstrap/AccordionToggle';
import AccordionContext from 'react-bootstrap/AccordionContext';
import Card from 'react-bootstrap/Card';
import 'bootstrap/dist/css/bootstrap.min.css';
function ContextAwareToggle({ children, eventKey, callback }) {
const currentEventKey = useContext(AccordionContext);
const decoratedOnClick = useAccordionToggle(
eventKey,
() => callback && callback(eventKey),
);
const isCurrentEventKey = currentEventKey === eventKey;
return (
<button
type="button"
style={{ backgroundColor: isCurrentEventKey ? 'pink' : 'lavender' }}
onClick={decoratedOnClick}
>
{children}
</button>
);
}
function App() {
return (
<Accordion defaultActiveKey="0">
<Card>
<Card.Header>
<ContextAwareToggle eventKey="0">Click me!</ContextAwareToggle>
</Card.Header>
<Accordion.Collapse eventKey="0">
<Card.Body>Hello! I'm the body</Card.Body>
</Accordion.Collapse>
</Card>
<Card>
<Card.Header>
<ContextAwareToggle eventKey="1">Click me!</ContextAwareToggle>
</Card.Header>
<Accordion.Collapse eventKey="1">
<Card.Body>Hello! I'm another body</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
);
}
export default App;
I even tried setting my own context like below
import React from 'react';
export default React.createContext(null);
But I'm still getting the same error!
Also, i have come across examples of using css to achieve this but i do not have a choice of using different libraries like fontawesome. Is there a better way to implement what I'm looking for? Thanks.

I figured it out and it was a silly mistake. i had to use {} around useAccordianToggle import statement as below.
import { useAccordionToggle } from 'react-bootstrap/AccordionToggle';

Related

breakpoints not working in MUI v5 and react project

I'm trying to use breakpoints for responsive design in my page, but it dosent really seem to work. Whenever i apply any breakpoint, the whole page goes blank.
Here's my code:-
Styles.js
import { makeStyles } from "#mui/styles";
const useStyles = makeStyles((theme) => ({
title: {
display: 'none',
[theme.breakpoints.up('sm')]: {
display: 'block',
},
},
}));
export default useStyles;
Header.jsx
import React from 'react';
import { Autocomplete } from '#react-google-maps/api';
import { AppBar, Toolbar, Typography, InputBase, Box } from '#mui/material';
import SearchIcon from '#mui/icons-material/Search';
import useStyles from './styles';
const Header = () => {
const classes = useStyles();
return (
<>
<AppBar position='static'>
<Toolbar className={classes.toolbar}>
<Typography variant='h5' className={classes.title}>
Travel Advisor
</Typography>
{/* Box acts as Div */}
<Box display='flex'>
<Typography variant='h6' className={classes.title}>
Explore new places
</Typography>
{/* <Autocomplete> */}
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase placeholder='Search...' classes={{ root: classes.inputRoot, input: classes.inputInput }} />
</div>
{/* </Autocomplete> */}
</Box>
</Toolbar>
</AppBar>
</>
)
}
export default Header;
Before applying breakpoints :-
Before breakpoint
After applying breakpoints :-
After breakpoint
Make sure that you created breakpoints correctly.
https://mui.com/material-ui/customization/breakpoints/
And check if you have wrapped your app in ThemeProvider.
And I want to note that #mui/styles is deprecated. Perhaps this problem may be related to this.
https://mui.com/system/styles/basics/
⚠️ #mui/styles is the legacy styling solution for MUI. It depends on JSS as a styling solution, which is not used in the #mui/material anymore, deprecated in v5. If you don't want to have both Emotion & JSS in your bundle, please refer to the #mui/system documentation which is the recommended alternative.
⚠️ #mui/styles is not compatible with React.StrictMode or React 18.
Dont use it on newly created app.

How to add an emoji button in react?

So I already did this basically 1 year ago but I forgot how to do it, and its not working now though. Here is the LINK
basically I have a like a "smile emoji icon button" and then when I click it I will pass the emoji in my text but it giving me now an error undefined. In the link you can see that it has same thing here.
import './App.scss';
import React, { useState } from 'react'
import 'bootstrap/dist/css/bootstrap.min.css';
import Picker from 'emoji-picker-react';
function App() {
const [chosenEmoji, setChosenEmoji] = useState(null);
const onEmojiClick = (event, emojiObject) => {
setChosenEmoji(emojiObject);
console.log(emojiObject)
};
return (
<div className="App">
<header className="App-header">
{/* {isLogin && user ? <LoginTrue/> : <LoginFalse/>} */}
{chosenEmoji ? (
<span>You chose: {chosenEmoji.emoji}</span>
) : (
<span>No emoji Chosen</span>
)}
<Picker onEmojiClick={onEmojiClick} />
</header>
</div>
);
}
export default App;
but the new update of emoji-picker-react did get different...Is anyone can give me an idea of it? or is there another source of importing emojis..I don't want to use Input-emoji-react its too ugly.
You may find it helpful but the way I personally did it on my project were I also used emoji-picker-react and MaterialUI is through native materialUI emoji icon button like this:
<div className="chat_footer">
{!emojiPicker ? (
<InsertEmoticonIcon onClick={() => setEmojiPicker((prev) => !prev)} />
) : (
<>
<InsertEmoticonIcon
onClick={() => setEmojiPicker((prev) => !prev)}
/>
<EmojiPicker
searchDisabled="true"
previewConfig={{ showPreview: false }}
emojiStyle="google"
onEmojiClick={(e) => setInput((input) => input + e.emoji)}
height={400}
width="40%"
/>
</>
)}
As I said, InsertEmoticonIcon is a MaterialUI icon which I import
Code sandbox link:
This link may help:
https://codesandbox.io/s/emoji-picker-react-4-forked-h846rd?file=/src/App.tsx
Onclick handler has to be Emoji and Event, not Event and then emoji

Reactstrap Collapse not working within React component

I've been trying to get my React component to work with the Collapse but I cannot seem to get my component to collapse correctly. Right now it will collapse temporarily when the div is clicked, but it will automatically reopen and not actually collapse any of the information needed. This component is taking multiple "modules" and turning them into their own cards. I've tried using a button instead of a div for the "onClick" and have tried with and without the reactstrap Card and CardBody components.
I'm thinking that the useState hook is somehow getting lost with my other props? Any help would be appreciated.
import React, { useState } from "react";
import { Container, Collapse, Card, CardBody } from "reactstrap";
import ReplayCard from "./ReplayCard";
import AttachmentCard from "./AttachmentCard";
const ModuleCard = (props) => {
const module = props.cardID;
const [isOpen, setIsOpen] = useState(false);
const toggle = () => setIsOpen(!isOpen);
return (
<div className="moduleCard">
<div onClick={toggle}>
<h2>{module.m_title}</h2>
<h5>Replay Date: {module.m_date}</h5>
</div>
<Collapse isOpen={isOpen}>
<h5>
{module.m_description}
</h5>
<h3>{module.m_title} Video(s)</h3>
<Container className="ReplayCard" fluid={true}>
{module.m_replay &&
module.m_replay.map((value, index) => {
return (
<ReplayCard
key={index}
cardID={index}
video={value.video}
text={value.text}
/>
);
})}
</Container>
<h3>{module.m_title} Link(s)</h3>
<Container className="AttachmentCard" fluid={true}>
{module.m_attachment &&
module.m_attachment.map((value, index) => {
return (
<AttachmentCard
key={index}
cardID={index}
text={value.text}
link={value.link}
/>
);
})}
</Container>
</Collapse>
</div>
);
};
export default ModuleCard;
The useState does seem to be changing from true to false when a console.log is inserted to the togged but still isn't actually triggering any changes.

filtering out onClick from a mapped array

I am trying to figure out how to filter out a mapped array and making the rest of the results disappear in the same component. I've done the same with React Router as I can route the result to a different page but I am wondering if there is a way to do the same on the same component? I have a Directory component (below) that is mapping through an array to display results of items on the page.
I would like to click on one of the elements and remove the rest. I tried to incorporate a filter method in the same component but drawing blanks on how I should implement it. Let me know what you think!
import React from 'react'
import { Card, CardImg} from 'reactstrap'
function Presentational({example, onClick}){
return(
<Card onClick={()=> onClick(example.name) }>
<CardImg src={example.image}/>
</Card>
)
}
function Directory(props){
const examples = props.propExample.map(example=>{
return (
<div>
<Presentational example={example} onClick={props.onClick} />
</div>
)
})
return(
<div>
{examples}
</div>
)
}
export default Directory;
You may use useState hook for selection
We store clicked elements inside the state variable selected. using useState hook.
When the user clicks on the element react component will remember which element he clicked and will render an array from 1 clicked element [selected].
In order to cleanup selection, just call setSelected()
It is the same logic as you want.
import React, {useState} from 'react'
import { Card, CardImg} from 'reactstrap'
function Presentational({example, onClick}){
return(
<Card onClick={()=> onClick(example.name) }>
<CardImg src={example.image}/>
</Card>
)
}
function Directory(props){
const [selected, setSelected] = useState()
const examples = (selected ? [selected] : props.propExample).map(example=>{
return (
<div>
<Presentational example={example} onClick={(name) => {
props.onClick(name)
setSelected(example)
}}
/>
</div>
)
})
return(
<div>
{examples}
</div>
)
}
export default Directory;
if you want to do it with a filter clause it will look almost the same, but with the extra operations
import React, {useState} from 'react'
import { Card, CardImg} from 'reactstrap'
function Presentational({example, onClick}){
return(
<Card onClick={()=> onClick(example.name) }>
<CardImg src={example.image}/>
</Card>
)
}
function Directory(props){
const [selected, setSelected] = useState()
const examples = props.propExample.filter(it => typeof selected === 'undefined' || it.name === selected).map(example=>{
return (
<div>
<Presentational example={example} onClick={(name) => {
props.onClick(name)
setSelected(name)
}}
/>
</div>
)
})
return(
<div>
{examples}
</div>
)
}
export default Directory;

Problems with React Router/Hoook

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

Categories