React component failed to render without any error or warning - javascript

I am writing a React component like this. My goal is to render a checklist for shopping, with toggles (lower order component) that would update the state of this higher order component when clicked.
It may look something like this
1.Fruits
Banana (Button)
Kiwi Fruit (Button)
2.Other snacks
Potato chips (Button)
Instant noodles (Button)
Sugarfree mint (Button)
let shopping_list = [
{
Fruits: [
{ Banana: "banana" },
{ "Kiwi fruit": "kiwi" },
]
},
{
'Other snacks': [
{ "Potato chips": "potato_chips" },
{ "Instant noodles ": "instant_noodles" },
{ "Sugarfree mint": "sugar_free_mint" }]
}
]
class ShoppingList extends Component {
constructor(props) {
super(props);
this.btnClicked.bind(this);
this.state = {
banana: false,
kiwi: false,
potato_chips: false,
instant_noodles: false,
sugar_free_mint: false,
}
}
btnClicked = (e) => {
let obj = {};
obj[e.currentTarget.id] = !(this.state[e.currentTarget.id]);
this.setState(obj);
}
createToggle = (content, attribute) => {
return (
<Row key={attribute}>
<Col>
{content}
</Col>
<Col xs="2">
<Chips label="✓"
id={attribute} onClick={this.btnClicked} />
</Col>
</Row>
)
}
createNestedToggle = (shopping_list) => {
//console.log("creating nested toggle")
//console.log(this)
shopping_list.map( (section, index) =>
( <React.Fragment key={index}>
<Row className="table_text" style={{paddingTop: 5}}>
<Col xs="12" style={{fontWeight: "bold"}}>
{index+1}.{(Object.keys(section))[0]}
</Col>
</Row>
{ (Object.values(section))[0].map((item) => {
this.createToggle(
(Object.keys(item))[0],
(Object.values(item))[0]
)
}
)
}
</React.Fragment>
))
}
render() {
return (
<div className="animated fadeIn">
<Title type="title" content="Shopping list" />
...
{/**Some rows and columns in here */}
<div>
{this.createNestedToggle(shopping_list)}
</div>
<div>
{/**Some rows and columns in here */}
</div>
</div>)
}
}
But the shopping list wasn't rendered properly, it was missing. When I was debugging, I tried adding console log messages to the function createNestedToggle as you can see, and they're actually logged. I am not sure what exactly is wrong with the second block.
Things I've tried
I have tried writing the createToggle part into a functional component to simplify the code - however,
as I need the toggles to call back the HOC I have to make createToggle a part of ShoppingList class.
I am quite new to React JS(JS to be exact), so maybe I am doing the whole thing in a way that's
completely wrong. If you could suggest me a better way to do it, I would be very grateful as well.
Any help or hint would be appreciated, thank you :)

After I have modified the createNestedToggle function as the following and it worked
createNestedToggle = (part_iii) => {
return(
<div>
{part_iii.map( (section, index) =>
<div key={index}>
...
{
(Object.values(section))[0].map((item) => {
return(
this.createToggle(
(Object.keys(item))[0],(Object.values(item))[0] )
)
}
)
}
</div>
)}
</div>
)
}
I was always confused by the arrow function notation and didn't realise that it has to be ()=>{...return ...} . (Yep I should read the docs more carefully) I will leave this post here in case any future Googlers need it. Thanks for everyone's answer.

Related

How to .Map over different props that are passed into a component?

I'm new to React but hopefully someone can help!
So I've just created a component that takes in a value (via prop) and then .maps over that value creating an Image slider. The props are all an array of objects that contain different values such as :
const Songs = [
{
artist: 'Artist Name',
song: 'Song Name',
lenght: '2:36',
poster: 'images/....jpg'
},
{
artist: 'Artist Name',
song: 'Song Name',
lenght: '2:36',
poster: 'images/....jpg'
},
]
I have been making the same component over and over again because I don't know how to make the 'prop'.map value dynamic. Essentially I don't know how to change the value before the .map each different prop.
Here's an example. I want to make 'Songs'.map dynamic so the new props can replace that so they can also be mapped. Maybe there's another way. Hopefully some can help.
import React from 'react';
import { FaCaretDown } from 'react-icons/fa';
function ImageSlider({Songs, KidsMovies, Movies, TvShows}) {
return (
<>
{Songs.map((image, index) => (
<div className="movie-card">
<img src={'https://image.tmdb.org/t/p/w500' + image.poster_path}
className='movie-img' />
<h5 className='movie-card-desc'>{image.original_title}</h5>
<p className='movie-card-overview'>{movie.overview}</p>
</div>
))}
</>
);
}
export default ImageSlider;
Given your example,
I feel like all you need is render ImageSlides for each array
function ImageSlider({ items }) {
return (
<>
{items.map((item, idx) => (
<div ... key={idx}> // be careful to not forget to put a key when you map components
...
</div>
))}
</>
);
}
When rendering your component
function OtherComponent({ songs, kidsMovies, movies, tvShows }) {
return (
<div>
<ImageSlider items={songs} />
<ImageSlider items={kidsMovies} />
<ImageSlider items={movies} />
<ImageSlider items={tvShows} />
</div>
);
}

how do i update my app sidebar dynamicaly

function TinderCards() {
const [people, setPeople] = useState([
{
name: "Model Baby",
url:"https://www.themodelskit.co.uk/wp-
content/uploads/2021/10/shutterstock_1431963185.jpg",
age:22
},
{
name: "Seema Jaswal",
url:"https://static.standard.co.uk/2021/06/14/16/euro_2020_live_seema_jaswal_01-1.jpg?
width=968&auto=webp&quality=50&crop=968%3A645%2Csmart",
age:32
},
{
name: 'Baby',
url: '../assets/IMG_20210811_105110_849.webp'
age: 34
}
]);
I am pullin data from a datebase that is like the data i created above for illustration purposes
useEffect(() => {
const allPeople = query(collection(db, "people"))
onSnapshot(allPeople, (snapshot) => (
setPeople(snapshot.docs.map((doc) => doc.data()))
))
return () => {
second
}
}, [])
I am updating the app with the information from the database
return (
<div>
<div className='tinderCards__cardContainer'>
{people.map((person) => (
<TinderCard className="swipe" key={person.name} preventSwipe={["up, down"]} onClick=
{() => {setPer(person.name)}} >
<div className='card' style={{ backgroundImage: `url(${person.url})`}}>
<h3>{person.name}</h3>
</div>
</TinderCard>
))}
</div>
</div>
)
}
export default TinderCards
but how do i update my sidebar with this infomatiom and have the name and other infomation change, eachtime the name changes in the main app
function RightSidebar() {
return (
<div className='rightSidebar'>
<div className='rightSidebar__contents'>
<h1>About</h1>
<Card className='rightSidebar__card'>
<div className='card__nameContents'>
<CardHeader className='card__nameAge' title = {name} subheader = {age}
avatar = {<VerifiedIcon className='activeIcon verified' />} />
<CardHeader className='card__active' title = "active" avatar=
{<FiberManualRecordIcon className='activeIcon' />} />
</div>
The app is quite small do i really need redux or is there a way to track the changes with useState hook?
How far is the common parent of RightSidebar and TinderCards?
If one level up or not too far, store the people data as state of the common parent, pass the data to right sidebar and a function to update the sidebar to TinderCards.
If common parent is far, you can use the React Context API (or the useContext hook).
You don't need redux for this

#szhsin/react-menu can't get Menu items inline, always one on top of another

I'm trying to get the Menu (from #szhsin/react-menu module) element buttons to show up to the right of the previous generated item, however I'm a bit lost as to how to get it to do so. Everything results in the element showing below previous.
import React from 'react';
import {
Menu,
MenuItem,
MenuButton,
SubMenu
} from '#szhsin/react-menu';
import '#szhsin/react-menu/dist/index.css'
class TopMenuDropdown extends React.Component {
constructor(props) {
super(props);
}
render () {
return (
<div>
{this.props.TMPMenuTestCategory.map (({name,items},i) =>
{
return <Menu
align={'end'}
key={i}
menuButton={<MenuButton>{name}</MenuButton>}
reposition={'initial'}
>
{items.map((item,j) =>
{
console.log(item,j);
return <MenuItem key={j}>{item}</MenuItem>
}
)}
</Menu>
} )}
</div>
)
}
}
I was looking through the documentation on https://szhsin.github.io/react-menu/docs , however, me trying the following has had no effect:
Assigning the display:'inline' or 'flex' the <Menu> or to a <div><Menu> as I attempted to give each menu it's own div when generated.
Wrapping each generated menu in a <span>
Fiddling with the Menu item's props like 'align' , 'position' , and 'reposition' (though I'm guessing Reposition needs an additional RepositionFlag to work if I understand it correctly)
Here's the snippet of index.JS it is part of
const basicMenuArray = [
{ name: 'ProTIS', items: [ 'Login', 'Exit' ] },
{ name: 'Project', items: [ 'Open', 'Info' ] },
]
class App extends React.Component {
state={
language:'sq'
}
render () {
return (
<div >
<div style={{display:'flex', width:'75%', float:'left' }}>
<span> Temp Text </span>
</div>
<div style={{display:'flex', width:'25%'}}>
<span style={{marginLeft:'auto'}}>
<DataComboBox
dropdownOptions={languages}
value={this.state.language}
valueField='language_code'
textField='language_full_name'
onChange={(value) => alert(JSON.stringify(value))}
/>
</span>
</div>
<div>
<TopMenuDropdown TMPMenuTestCategory={basicMenuArray} />
</div>
</div>
);
}
}
So I ended up realizing something this morning, as I'm learning ReactJS still, and my brain did not process the things properly.
I changed the initial
<div>
to
<div style={{display:'flex'}}>
and added a style={{display:'flex', float:'left'}} to the <Menu> which generates the button.
the final code snippet looks like this for anyone still learning like I am :)
return (
<div style={{display:'flex'}}>
{this.props.TMPMenuTestCategory.map (({name,items},i) =>
{
return <Menu
style={{display:'flex', float:'left'}}
key={i}
menuButton={<MenuButton>{name}</MenuButton>}
>
{items.map((item,j) =>
{
console.log(item,j);
return <MenuItem key={j}>{item}</MenuItem>
}
)}
</Menu>
} )}
</div>
)

Reactjs style component with document.getElementById

Hello i'm trying to highlight the Items, with the same Id. Im using document.getElementById but i don't really know ho to do it. does anyone can help me?
I'm iterating over an Array of Objects from my Database....
return(
<div className='list'>
<Row>
{this.state.cards.map((card) => {
return(<Card
onHover={()=>{
const highlighted = document.getElementById(card.id)
highlighted.style={{backgroundColor: "blue"}}
}}
cardHeading={card.cardHeading} cardDesc={card.cardDesc}
cardPreis={card.cardPreis} cardId={card.id} bewertung={card.cardBewertung}
image={card.cardImage}/>)
})
}
</Row>
</div>
)
.... My GoogleMaps Component:
<Marker onClick={props.show}
position={{ lat: marker.latitude + 0.00201, lng:
marker.longitude + 0.00201}}
id={marker.id}
/>
id={marker.id} and cardId={card.id} are the same and i want to highlight one of them when hovering over them ... thanks in advance.
React gives you the ability for a component to control itself dynamically. So make that Card into a separate component with all of the logic you need using this.setState to control the current style of your Card. I can't test this, but this is the general idea:
return(
<div className='list'>
<Row>
{this.state.cards.map((card) => <CustomCard card={card}/>)}
</Row>
</div>
)
class CustomCard extends Component {
constructor() {
super()
this.state = {
defaultColor: true
}
}
handleClickColorChange() {
this.setState({defaultColor: !this.state.defaultColor})
}
render() {
const {card} = this.props
const customStyle = {
backgroundColor: 'blue'
}
return (
<Card
onHover={() => this.handleClickColorChange()}
style={this.state.defaultColor ? null : customStyle}
cardHeading={card.cardHeading} cardDesc={card.cardDesc}
cardPreis={card.cardPreis} cardId={card.id} bewertung={card.cardBewertung}
image={card.cardImage}
/>
)
}
}

React pass props from multiple arrays in state

I am trying to pass props from two arrays that are contained in the state of the react component. One array is generated by the user and the other is already built in. This is a bit over my head as I'm still new to React and am unsure how to correctly pass props.
There are no errors here in the component, it's just that I don't know how to do it.
I will explain below what I'm looking for, any help would be greatly appreciated
Main Component
In this.state below you will see questions (which works perfectly) then hints. Questions is mapped over correctly however when I try to add in hints to map along with it, it returns all of the hints at once instead of in order and one by one. I've tried just adding (questions, hints) but it doesn't return it correctly.
export default class AutoFocusText extends Component {
constructor() {
super();
this.state = {
active: 0,
questions: [
'1. Enter A Proper Noun',
'2. Enter A Location',
'3. Enter A Proper Noun that Describes Evil',
'4. Describe Something Menacing',
'5. Describe a fortified area',
"6. A Woman's Name",
'7. Describe a large area of mass'
],
hints: [
"Hint: Use words like Rebel, Hell's Angels",
'Hint: Use a word such as Base, Bunker, Foxhole, Bedroom',
'Hint: Use words like Empire, Ottoman, Mongols',
'Hint: Freeze Ray, Leftover Fruitcake',
'Hint: Castle, Bunker, Planet',
'Hint: Astrid, Diana, Mononoke, Peach',
'Hint: Use words such as Galaxy, Planet, Wal Mart'
],
answers: []
};
I'd like to take the user's inputs of answers and have it passed along as props into another component such as properName1={this.state.value1} and so on, I know that's mapping an array of answers, I'm just unsure how to do this.
Below is the rest of the main component.
this.submitHandler = this.submitHandler.bind(this);
this.renderQuestion = this.renderQuestion.bind(this);
this.onChange = this.onChange.bind(this);
}
renderQuestion() {
const { questions, hints, active, value } = this.state;
if (active >= questions.length)
return <Crawler style={{ width: '500px', position: 'absolute' }} />;
return questions.filter((quest, index) => index === active).map(quest => ( // get next question // map over selected question, the key prop allows react to
<FormElement
key={active}
text={quest}
hint={hints}
value={value}
onChange={this.onChange}
/>
));
}
onChange(e) {
this.setState({ value: e.target.value });
}
submitHandler(e) {
e.preventDefault();
const answers = [...this.state.answers, this.state.value]; //push new value to answsers array without mutation
const value = ''; // clear input
const active = this.state.active + 1; // index pointer
this.setState({ answers, value, active });
}
render() {
return (
<MainContainer>
<DivStyle>
{/* Form Wrapper */}
<form onSubmit={this.submitHandler}>
{this.renderQuestion()}
<SubmitButton type="submit">Submit</SubmitButton>
</form>
<ul>
{this.state.answers.map((ans, index) => {
return (
<li key={index}>
{ans}
</li>
);
})}
</ul>
</DivStyle>
</MainContainer>
);
}
}
Child Component 1
This is the dumb component where the questions (and where I want the hints as well) generated
class FormElement extends Component {
constructor() {
super();
}
componentDidMount() {
//focus text input upon mounting component
this.textInput.focus();
}
render() {
const { text, hint, value, onChange } = this.props;
return (
<div>
<InputQuestion>
{text}
{hint}
</InputQuestion>
<input
className="inputstyling"
ref={el => {
this.textInput = el;
}}
onChange={onChange}
type="text"
value={value}
/>
</div>
);
}
}
export default FormElement;
At the moment, "hint" brings in all the hints at once, instead of one at a time and in order.
Child Component 2
Finally the props needed to pass go here. The array is throwing me as I've never passed props via an array
class Crawler extends Component {
constructor() {
super();
this.state = {
properName1: 'Rebel',
noun1: 'frog',
properName2: 'Empire',
properName3: 'DEATH STAR',
noun2: 'station',
noun3: 'planet',
personsName1: 'Leia',
noun4: 'starship',
pluralnoun1: 'people',
noun5: 'galaxy'
};
}
render() {
return (
<ContainLeft style={{ padding: 0 }}>
<CrawlHolder>
<div class="fade" />
<section className="star-wars">
<div className="crawl">
<div className="title">
<p>Episode IV</p>
<h1>A New Hope</h1>
</div>
<p>
It is a period of civil war.
{' '}
{this.props.properName1}
{' '}
spaceships, striking from a hidden
{' '}
{this.props.noun1}
, have won their first victory against the evil Galactic
{' '}
{this.props.properName2}
.
</p>
<p>
During the battle,
{' '}
{this.props.properName1}
{' '}
spies managed to steal secret plans to the
{' '}
{this.props.properName2}
's ultimate weapon, the
{' '}
{this.props.properName3}
, an armored
{' '}
{this.props.noun2}
{' '}
with enough power to destroy an entire planet.
</p>
<p>
Pursued by the Empire’s sinister agents, Princess
{' '}
{this.props.personsName1}
{' '}
races home aboard her starship, custodian of the stolen plans that can save her people and restore freedom to the
{' '}
{this.props.noun3}
…
</p>
</div>
</section>
</CrawlHolder>
</ContainLeft>
);
}
}
export default Crawler;
Thank you for your help
the function in map has an optional second param, the index of the current element so you could do:
return questions.filter((quest, index) => index === active).map((quest,i) => (
<FormElement
key={active}
text={quest}
hint={hints[i]}
value={value}
onChange={this.onChange}
/>
));
EDIT:
I see now you are rendering only one question at a time so a map isn't needed I think; since you have the index of the current question (active) I think you could just
return (
<FormElement
text={questions[active]}
hint={hints[active]}
value={value}
onChange={this.onChange}
/>
)

Categories

Resources