React conditionally render a div - reactjs

I am trying to add a hint option to my quiz app.
If the 50/50 button is clicked I want to render the newAnswers array. else I want to render the shuffledAnswers array.
when I run this code I get
TypeError: Cannot read properties of null (reading 'useState')
What am I doing wrong here?
import React from "react";
import { useState } from "react/cjs/react.production.min";
import Card from "../UI/Card";
import "./DisplayQuestion.css";
import ProgressBar from "./Progress";
const DisplayQuestion = (props) => {
/*I used dangerouslySetInnerHTML to fix the quotes gibberish problem */
const [hint, setHint] = useState(false);
console.log("hint: ", hint);
let notBoolean = false;
const newAnswers = [
props.data.correct_answer,
props.data.incorrect_answers[0],
];
/*Helper functions */
// shuffles the answers
let shuffledAnswers = [
props.data.correct_answer,
...props.data.incorrect_answers,
].sort(() => Math.random() - 0.5);
if (shuffledAnswers.length > 2) {
notBoolean = true;
console.log("notBoolean");
}
const answersHintHandler = () => {
setHint(true);
console.log("hint: ", hint);
console.log(newAnswers);
};
let progress = Math.round((props.score / props.numOfQuestions) * 100);
return (
<div>
<h3 class="diff">Difficulty: {props.diff}</h3>
<div classname="Questions">
<Card>
<ProgressBar bgcolor="#99ccff" progress={progress} height={30} />
<h2>
Questions {props.index}/{props.numOfQuestions}
</h2>
<h2
className="question-text"
dangerouslySetInnerHTML={{
__html: props.data.question,
}}
/>
<ul>
{notBoolean ? (
<button onClick={answersHintHandler}>50/50</button>
) : (
<p></p>
)}
{hint
? newAnswers.map((answer) => {
return (
<li
onClick={() => props.handler(answer)}
dangerouslySetInnerHTML={{
__html: answer,
}}
></li>
);
})
: shuffledAnswers.map((answer) => {
return (
<li
onClick={() => props.handler(answer)}
dangerouslySetInnerHTML={{
__html: answer,
}}
></li>
);
})}
</ul>
</Card>
</div>
</div>
);
};
export default DisplayQuestion;

Replace 1st and 2nd line with
import React, { useState } from 'react'

You are importing useState from the wrong path x)
import { useState } from "react/cjs/react.production.min";
Care the automatic imports haha

Related

How to fix (Uncaught Error: Cannot find module './undefined.jpg') in React.js

I would appreciate to know why it gives this './undefined.jpg' before anything else and only AFTER that, renders all the actual paths.
import { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';
import style from './CarsListPage.module.scss';
//import cars from './car-content';
import CarsList from '../components/CarsList';
const CarsListPage = () => {
const [carsInfo, setCarsInfo] = useState([{}]);
useEffect(() => {
const loadCarsInfo = async () => {
const response = await axios.get('/api/cars');
const newCarsInfo = response.data;
setCarsInfo(newCarsInfo);
};
loadCarsInfo();
}, []);
return (
<div className={style.mainCotainer}>
<main className={style.main}>
<h1>Cars</h1>
<div className={style.container}>
{carsInfo.map((car) => (
<Link to={`/cars/${car.name}`} key={car.id}>
<div className={style.card} key={car.id}>
<h3>{car.name}</h3>
{/* {console.log(`../temp-img/${car.title}.jpg`)} */}
<p>{car.body_type}</p>
<p>{car.origin}</p>
<p>{car.year}</p>
<img
src={require(`../temp-img/${car.title}.jpg`)}
alt={car.name}
style={{ width: '200px' }}
/>
</div>
</Link>
))}
</div>
</main>
</div>
);
};
export default CarsListPage;
I've found couple solutions like wrapping everying into div and check whether value exists or not but i could not optimize it for my code.
Change the default state of carsInfo to [] otherwise you will map on an empty object until you get the data from the API:
const CarsListPage = () => {
const [carsInfo, setCarsInfo] = useState([]);
useEffect(() => {
const loadCarsInfo = async () => {
const response = await axios.get('/api/cars');
const newCarsInfo = response.data;
setCarsInfo(newCarsInfo);
};
loadCarsInfo();
}, []);
return (
<div className={style.mainCotainer}>
<main className={style.main}>
<h1>Cars</h1>
<div className={style.container}>
{carsInfo.length && carsInfo.map((car) => (
<Link to={`/cars/${car.name}`} key={car.id}>
<div className={style.card} key={car.id}>
<h3>{car.name}</h3>
{/* {console.log(`../temp-img/${car.title}.jpg`)} */}
<p>{car.body_type}</p>
<p>{car.origin}</p>
<p>{car.year}</p>
<img
src={require(`../temp-img/${car.title}.jpg`)}
alt={car.name}
style={{ width: '200px' }}
/>
</div>
</Link>
))}
</div>
</main>
</div>
);
};

SlateJS React trying to get a textfield to work inside an Element

I have a Slate element that looks like this:
import React, {useState} from 'react'
import "./App.css"
export default function Accordion(props) {
const [closed, setClosed] = useState(false) //todo eventually fetch starting position from savefile
const [heightClass, setHeightClass] = useState("")
const handleToggle = () => {
if(closed === false){
setHeightClass("h-0")
}
else{
setHeightClass("")
}
setClosed(!closed)
}
return (
<>
<div {...props.attributes}>
{/* title and button */}
<div className='flex justify-between '>
<div className='font-semibold'>
<DefaultElement {...props}/> //the title of the accordion
</div>
<div
className={`px-2 cursor-pointer font-bold font-mono select-none ${closed ? "rotate-180" : ""}`}
onClick={() => {
handleToggle()
}}>
V
</div>
</div>
{/* ${closed ? "h-0" : ""} */}
<div className={`rounded border-l px-2 overflow-hidden accordionTransition `}
style={{height: closed ? "0px" : ""}}>
{props.children}
</div>
</div>
</>
)
}
const DefaultElement = props => {
console.log(props)
return <p {...props.attributes}>
{props.children}
</p>
}
Which is used by the Editor in App.js:
const App = () => {
const [editor] = useState(() => withReact(createEditor()))
// Define a rendering function based on the element passed to `props`. We use
// `useCallback` here to memoize the function for subsequent renders.
const renderElement = useCallback(props => {
switch (props.element.type) {
case 'accordion':
return <Accordion {...props} />
default:
return <DefaultElement {...props} />
}
}, [])
return (
<div className='p-5'>
<Slate editor={editor} value={initialValue}>
<Editable
// Pass in the `renderElement` function.
renderElement={renderElement}
/>
</Slate>
</div>
)
}
const DefaultElement = props => {
return <span {...props.attributes}>
{props.children}
</span>
}
export default App;
I'm trying to get the Accordion title to be properly editable and work as Slate intended. Just a a simple textfield. I can't figure out the correct syntax and how i'm supposed to do this.
When i do this, the title and the accordion content (props.children) are the same. I don't understand why.
If i remove the <DefaultElement {...props}/> and just write some text, it throws me this error when i edit it: Uncaught Error: Cannot resolve a Slate point from DOM point: [object Text],4

React Each child in a list should have a unique "key" prop. even if the key is present

I have the following react component where I set the keys on render with uuid but still getting the warning index.js:1 Warning: Each child in a list should have a unique "key" prop.
import React, { useEffect, useState } from "react";
import { v4 as uuidv4 } from "uuid";
const Breadcrumbs = (props) => {
const { path, lang } = props;
const [breadcrumbsItems, setBreadcrumbsItems] = useState(null);
useEffect(() => {
if (path) {
const content = path.map((item, index) => {
if (!item.text) return null;
const isLast = index + 1 === path.length ? true : false;
return (
<>
{isLast ? (
<span key={uuidv4()} className={"post post-jobs current-item"}>
{item.text}
</span>
) : (
<span key={uuidv4()} property="itemListElement" typeof="ListItem">
<a
property="item"
typeof="WebPage"
title={item.title}
href="/"
className="home"
>
<span property="name">{item.text}</span>
</a>
</span>
)}
</>
);
});
setBreadcrumbsItems(content);
}
}, [path]);
return (
<div key={uuidv4()}>
{breadcrumbsItems ? (
<div className="breadcrumbs uk-visible#m">
{breadcrumbsItems && breadcrumbsItems}
</div>
) : null}
</div>
);
};
export default Breadcrumbs;
What is wrong in this case with my code?
I think this is because the main child is your Fragment (<>).
You have to provide the key property to the main element you return from your map function.
Try to change your return to something like this:
<Fragment key={uuidv4()}>
{isLast ? (
<span className={"post post-jobs current-item"}>
{item.text}
</span>
) : (
<span property="itemListElement" typeof="ListItem">
<a
property="item"
typeof="WebPage"
title={item.title}
href="/"
className="home"
>
<span property="name">{item.text}</span>
</a>
</span>
)}
</Fragment>
And do not forget to import Fragment from react:
import { Fragment } from 'react';

Getting error when adding a function to my react app

I'm new to react and followed a tutorial to do a shopping cart. In the end, I added a function that would give me the total cost of the products, but I get an error when adding products and clicking on Cart "productList.reduce is not a function". You can see this function (getTotalCost) in Cart. I tried to solve this but I get other errors. These are my files:
ProductsPage :
import React, {useState} from 'react'
import './ProductsPage.css'
import Products from '../../components/Products'
import Cart from '../../components/Cart'
const PAGE_PRODUCTS = 'products';
const PAGE_CART = 'cart';
function ProductsPage() {
const [cart, setCart] = useState ([]);
const [page, setPage] = useState (PAGE_PRODUCTS);
const addToCart = (product) => {
setCart ([...cart, {...product}])
}
const removeFromCart = (productToRemove) => {
setCart(cart.filter(product => product !== productToRemove))
}
const navigateTo = (nextPage) => {
setPage(nextPage);
};
return (
<div className="productspage">
<header>
<button className="cart-btn" onClick={()=> navigateTo(PAGE_CART)}>
Go to Cart ({cart.length})
</button>
<button className="products-btn" onClick={()=> navigateTo(PAGE_PRODUCTS)}>
View Products
</button>
</header>
{page === PAGE_PRODUCTS && <Products addToCart={addToCart}/>}
{page === PAGE_CART && <Cart cart={cart} removeFromCart={removeFromCart} />}
<div>
</div>
</div>
);
};
export default ProductsPage;
Products:
import React, {useState} from 'react'
function Products ({ addToCart }) {
const [products] = useState ([
{
name: 'Breakfast ',
cost:'9.99$',
image: 'https://images.unsplash.com/photo-1569420067112-b57b4f024595?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80',
},
{
name: 'Breakfast box ',
cost:'8.99$',
image: 'https://images.unsplash.com/photo-1569419910356-f63064754fc9?ixlib=rb-1.2.1&auto=format&fit=crop&w=700&q=80',
},
{
name: 'Snack box ',
cost:'6.99$',
image: 'https://images.unsplash.com/photo-1569419882964-7db5d339951b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80',
},
{
name: '4 small breakfast bowls ',
cost:'9.99$',
image: 'https://images.unsplash.com/photo-1570649857669-4ad9f896435d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=703&q=80',
}
])
return (
<>
<h1 className="products-title">Products</h1>
<div className="products">
{products.map((product , index) => (
<div className="product" key={index}>
<h3>{product.name}</h3>
<h4>{product.cost}</h4>
<img src={product.image} alt={product.name}/>
<p></p>
<button onClick={() => addToCart(product)}>
Add to Cart
</button>
</div>
))}
</div>
</>
)
}
export default Products;
Cart
import React from 'react'
import products from '../../components/Products'
function Cart ({ cart, removeFromCart }) {
const getTotalCost = (productList) => (
productList.reduce((totalCost, { cost: itemCost }) => totalCost += parseFloat(itemCost), 0)
);
return (
<>
<h1>Cart</h1>
<div className="products">
{cart.map((product , index) => (
<div className="product" key={index}>
<h3>{product.name}</h3>
<h4>{product.cost}</h4>
<img src={product.image} alt={product.name}/>
<button onClick={() => removeFromCart(product)}>
Remove
</button>
{getTotalCost(products)}
</div>
))}
</div>
</>
)
}
export default Cart;
In the second code snippet, where you are calling {getTotalCost(products)}, you are using the products component you are importing on line 2, which is a Component, not a List, so the reduce function does not exist on it, which is why you're seeing that error.
You probably want {getTotalCost(cart)} instead.

Building Dropdown component

I'm having a problem building a dropdown component. In the function to get the selected item I'm having this error :
Too many re-renders. React limits the number of renders to prevent an
infinite loop.
The code for the component :
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import '../../../App.css'
function Dropdown({ items }) {
//const [list, setList] = useState(items);
const [selectedItem, setSelectedItem] = useState(items[0]);
const [showItems, setShowItem] = useState(false);
const [setExpand, setExpandState] = useState("");
function toggleDropdown() {
setExpandState(setExpand === "" ? "dropdown-expanded dropdown-expanded-down" : "");
setShowItem(showItems === false ? true : false);
};
const Changed = (item) => {
setShowItem(false);
setSelectedItem(item);
}
return (
<div data-dropdown="" className={`dropdown-container dropdown ${setExpand}`} onClick={toggleDropdown} >
<div className="dropdown-display">
<div className="dropdown-display-content" >
<span data-expression="" class="OSFillParent"> {selectedItem.value} </span>
</div>
</div>
<div className="dropdown-list" style={{ display: showItems ? 'block' : 'none' }} >
<div className="scrollable-list scrollable-list-with-scroll">
{items.map(item =>
<div className="dropdown-popup-row" key={item.id} onClick={Changed(item)} > {item.value} </div>
)}
</div>
</div>
</div>
);
}
Dropdown.propTypes = {
items: PropTypes.array,
}
export default Dropdown;
The problem is on here onClick={Changed(item)}
You are calling this on each render, and it's modifying the state every render, so it gets called again recursively.
You can solve it by doing:
<div className="dropdown-popup-row"
key={item.id}
onClick={() => Changed(item)}>
{item.value}
</div>

Resources