I might be missing something, but after struggling a bit, I followed a tutorial showing the basics of props. My prop is passing, but all my variables are returning as undefined. Im trying to pass my calculations to a component to display the total.
My calculation component (IncomeAndexpenses.js)
import {useState, useEffect} from 'react';
import HeadSection from '../HeadSection';
const IncomeVals = () => {
const [TotIncome, settotIncome] = useState(0);
const [totTaxBrackets ,settotTaxBrackets] = useState(0);
const [AvValues ,setAvValues] = useState();
const Users= [{
name: 'Johan Golden', salary: 60000
}, {
name: 'Susan Golden', salary: 27000
}
]
const expenses= [{
name: 'Johan Golden', salary: 60000
}, {
name: 'Susan Golden', salary: 27000
}
]
useEffect(() => {
let totalIcome = 0;
let totalIcomeTax = 0;
Users.forEach(element => {
totalIcome += element.salary;
});
console.log(totalIcome);
settotIncome(totalIcome);
//taxBrackets
totalIcome = totalIcome * 12;
console.log(totalIcome);
}, []);
return (
<>
<HeadSection name="josh" totalIncome = {TotIncome}/>
</>
)
}
export default IncomeVals;
And then displaying on this component (HeadSection)
import React from "react";
const HeadSection = (props) => {
console.log(props.name);
return (
<div className='SectionOne'>
<hr></hr>
<div className='subSections'>
<div className='subSection'><h3>Total Income</h3><br></br><h2>R{props.totalIncome}</h2></div>
<div className='subSection'><h3>Total Expenses</h3><br></br><h2>R13 327</h2></div>
<div className='subSection'><h3>Total Income after tax</h3><br></br><h2>R65 560</h2></div>
</div>
<hr></hr>
</div>
)
}
export default HeadSection;
Any help would be much appreciated!
Related
I have a componenet that wraps its children and slides them in and out based on the stage prop, which represents the active child's index.
As this uses a .map() to wrap each child in a div for styling, I need to give each child a key prop. I want to assign a random key as the children could be anything.
I thought I could just do this
key={`pageSlide-${uuid()}`}
but it causes an infinite loop/React to freeze and I can't figure out why
I have tried
Mapping the children before render and adding a uuid key there, calling it via key={child.uuid}
Creating an array of uuids and assigning them via key={uuids[i]}
Using a custom hook to store the children in a state and assign a uuid prop there
All result in the same issue
Currently I'm just using the child's index as a key key={pageSlide-${i}} which works but is not best practice and I want to learn why this is happening.
I can also assign the key directly to the child in the parent component and then use child.key but this kinda defeats the point of generating the key
(uuid is a function from react-uuid, but the same issue happens with any function including Math.random())
Here is the full component:
import {
Children,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import PropTypes from "prop-types";
import uuid from "react-uuid";
import ProgressBarWithTicks from "./ProgressBarWithTicks";
import { childrenPropType } from "../../../propTypes/childrenPropTypes";
const calculateTranslateX = (i = 0, stage = 0) => {
let translateX = stage === i ? 0 : 100;
if (i < stage) {
translateX = -100;
}
return translateX;
};
const ComponentSlider = ({ stage, children, stageCounter }) => {
const childComponents = Children.toArray(children);
const containerRef = useRef(null);
const [lastResize, setLastResize] = useState(null);
const [currentMaxHeight, setCurrentMaxHeight] = useState(
containerRef.current?.childNodes?.[stage]?.clientHeight
);
const updateMaxHeight = useCallback(
(scrollToTop = true) => {
if (scrollToTop) {
window.scrollTo(0, 0);
}
setCurrentMaxHeight(
Math.max(
containerRef.current?.childNodes?.[stage]?.clientHeight,
window.innerHeight -
(containerRef?.current?.offsetTop || 0) -
48
)
);
},
[stage]
);
useEffect(updateMaxHeight, [stage, updateMaxHeight]);
useEffect(() => updateMaxHeight(false), [lastResize, updateMaxHeight]);
const resizeListener = useMemo(
() => new MutationObserver(() => setLastResize(Date.now())),
[]
);
useEffect(() => {
if (containerRef.current) {
resizeListener.observe(containerRef.current, {
childList: true,
subtree: true,
});
}
}, [resizeListener]);
return (
<div className="w-100">
{stageCounter && (
<ProgressBarWithTicks
currentStage={stage}
stages={childComponents.length}
/>
)}
<div
className="position-relative divSlider align-items-start"
ref={containerRef}
style={{
maxHeight: currentMaxHeight || null,
}}>
{Children.map(childComponents, (child, i) => (
<div
key={`pageSlide-${uuid()}`}
className={`w-100 ${
stage === i ? "opacity-100" : "opacity-0"
} justify-content-center d-flex`}
style={{
zIndex: childComponents.length - i,
transform: `translateX(${calculateTranslateX(
i,
stage
)}%)`,
pointerEvents: stage === i ? null : "none",
cursor: stage === i ? null : "none",
}}>
{child}
</div>
))}
</div>
</div>
);
};
ComponentSlider.propTypes = {
children: childrenPropType.isRequired,
stage: PropTypes.number,
stageCounter: PropTypes.bool,
};
ComponentSlider.defaultProps = {
stage: 0,
stageCounter: false,
};
export default ComponentSlider;
It is only called in this component (twice, happens in both instances)
import { useEffect, useReducer, useState } from "react";
import { useParams } from "react-router-dom";
import {
FaCalendarCheck,
FaCalendarPlus,
FaHandHoldingHeart,
} from "react-icons/fa";
import { IoIosCart } from "react-icons/io";
import { mockMatches } from "../../../templates/mockData";
import { initialSwapFormState } from "../../../templates/initalStates";
import swapReducer from "../../../reducers/swapReducer";
import useFetch from "../../../hooks/useFetch";
import useValidateFields from "../../../hooks/useValidateFields";
import IconWrap from "../../common/IconWrap";
import ComponentSlider from "../../common/transitions/ComponentSlider";
import ConfirmNewSwap from "./ConfirmSwap";
import SwapFormWrapper from "./SwapFormWrapper";
import MatchSwap from "../Matches/MatchSwap";
import SwapOffers from "./SwapOffers";
import CreateNewSwap from "./CreateNewSwap";
import smallNumberToWord from "../../../functions/utils/numberToWord";
import ComponentFader from "../../common/transitions/ComponentFader";
const formStageHeaders = [
"What shift do you want to swap?",
"What shifts can you do instead?",
"Pick a matching shift",
"Good to go!",
];
const NewSwap = () => {
const { swapIdParam } = useParams();
const [formStage, setFormStage] = useState(0);
const [swapId, setSwapId] = useState(swapIdParam || null);
const [newSwap, dispatchNewSwap] = useReducer(swapReducer, {
...initialSwapFormState,
});
const [matches, setMatches] = useState(mockMatches);
const [selectedMatch, setSelectedMatch] = useState(null);
const [validateHook, newSwapValidationErrors] = useValidateFields(newSwap);
const fetchHook = useFetch();
const setStage = (stageIndex) => {
if (!swapId && stageIndex > 1) {
setSwapId(Math.round(Math.random() * 100));
}
if (stageIndex === "reset") {
setSwapId(null);
dispatchNewSwap({ type: "reset" });
}
setFormStage(stageIndex === "reset" ? 0 : stageIndex);
};
const saveMatch = async () => {
const matchResponse = await fetchHook({
type: "addSwap",
options: { body: newSwap },
});
if (matchResponse.success) {
setStage(3);
} else {
setMatches([]);
dispatchNewSwap({ type: "setSwapMatch" });
setStage(1);
}
};
useEffect(() => {
// set matchId of new selected swap
dispatchNewSwap({ type: "setSwapMatch", payload: selectedMatch });
}, [selectedMatch]);
return (
<div>
<div className="my-3">
<div className="d-flex justify-content-center w-100 my-3">
<ComponentSlider stage={formStage}>
<IconWrap colour="primary">
<FaCalendarPlus />
</IconWrap>
<IconWrap colour="danger">
<FaHandHoldingHeart />
</IconWrap>
<IconWrap colour="warning">
<IoIosCart />
</IconWrap>
<IconWrap colour="success">
<FaCalendarCheck />
</IconWrap>
</ComponentSlider>
</div>
<ComponentFader stage={formStage}>
{formStageHeaders.map((x) => (
<h3
key={`stageHeading-${x.id}`}
className="text-center my-3">
{x}
</h3>
))}
</ComponentFader>
</div>
<div className="mx-auto" style={{ maxWidth: "400px" }}>
<ComponentSlider stage={formStage} stageCounter>
<SwapFormWrapper heading="Shift details">
<CreateNewSwap
setSwapId={setSwapId}
newSwap={newSwap}
newSwapValidationErrors={newSwapValidationErrors}
dispatchNewSwap={dispatchNewSwap}
validateFunction={validateHook}
setStage={setStage}
/>
</SwapFormWrapper>
<SwapFormWrapper heading="Swap in return offers">
<p>
You can add up to{" "}
{smallNumberToWord(5).toLowerCase()} offers, and
must have at least one
</p>
<SwapOffers
swapId={swapId}
setStage={setStage}
newSwap={newSwap}
dispatchNewSwap={dispatchNewSwap}
setMatches={setMatches}
/>
</SwapFormWrapper>
<SwapFormWrapper>
<MatchSwap
swapId={swapId}
setStage={setStage}
matches={matches}
selectedMatch={selectedMatch}
setSelectedMatch={setSelectedMatch}
dispatchNewSwap={dispatchNewSwap}
saveMatch={saveMatch}
/>
</SwapFormWrapper>
<SwapFormWrapper>
<ConfirmNewSwap
swapId={swapId}
setStage={setStage}
selectedSwap={selectedMatch}
newSwap={newSwap}
/>
</SwapFormWrapper>
</ComponentSlider>
</div>
</div>
);
};
NewSwap.propTypes = {};
export default NewSwap;
One solution
#Nick Parsons has pointed out I don't even need a key if using React.Children.map(), so this is a non issue
I'd still really like to understand what was causing this problem, aas far as I can tell updateMaxHeight is involved, but I can't quite see the chain that leads to an constant re-rendering
Interstingly if I use useMemo for an array of uuids it works
const uuids = useMemo(
() => Array.from({ length: childComponents.length }).map(() => uuid()),
[childComponents.length]
);
/*...*/
key={uuids[i]}
Hello I'm trying to display the content of an object on my html page using react. I managed to access the frontend property that are in my object array. Now when I try to browse each element of my frontend object array and display the id of each element on my page it displays only the first element which is "HTML". But I want to display all the other id on the page. I don't know what is the problem
The external data
const skills = [
{
frontend: [
{
id: 'HTML',
img: './images/skills/html5.svg'
},
{
id: 'CSS',
img: './images/skills/css3.svg'
},
{
id: 'Javascript',
img: './images/skills/javascript.svg'
},
{
id: 'Bootstrap',
img: './images/skills/bootstrap.svg'
},
{
id: 'React JS',
img: './images/skills/react.svg'
},
{
id: 'Flutter',
img: './images/skills/flutter.svg'
},
],
backend: [
{
id: 'PHP',
img: './images/skills/php.svg'
},
{
id: '.NET Core',
img: './images/skills/net-core.svg'
},
{
id: 'Node JS',
img: './images/skills/html5.svg'
},
],
languages: [
{
id: 'Java',
img: './images/skills/java.svg'
},
{
id: 'Python',
img: './images/skills/python.svg'
},
{
id: 'C#',
img: './images/skills/csharp.svg'
},
],
},
];
export default skills;
My home file
import React, { useEffect, useState } from "react";
import "../styles/Home.css";
import Skills from "../data/Skills";
export const Home = () => {
const [skills, setSkills] = useState([]);
useEffect(() => {
setSkills(Skills);
}, []);
const frontend = skills.map((element) => {
return element.frontend;
});
console.log(frontend);
return (
<div className="home">
<div className="skills">
<h1>Skills</h1>
{frontend.map((item, index) => {
console.log(index)
return <ul key={index}>
<li>{item[index].id}</li>
</ul>;
})}
</div>
</div>
);
};
The result is here
If you are already importing data, you don't need to store that into a state,
Try this ,
import React, { useEffect, useState } from "react";
import "./styles.css";
import Skills from "./Skills";
export const Home = () => {
let frontend = [];
Skills.forEach((skill) => {
frontend = [...frontend, ...skill.frontend];
});
return (
<div className="home">
<div className="skills">
<h1>Skills</h1>
{frontend.map((item, index) => {
return (
<ul key={item.id}>
<li>{item.id}</li>
</ul>
);
})}
</div>
</div>
);
};
Try this,
Change data file to
const skills = {
frontend: [...],
backend: [...],
languages: [...],
};
export default skills;
Code
import React, { useEffect, useState } from "react";
import "../styles/Home.css";
import Skills from "../data/Skills";
export const Home = () => {
return (
<div className="home">
<div className="skills">
<h1>Skills</h1>
{Skills.frontend.map(item => <ul key={item.id}>
<li>{item.img}</li>
</ul>}
</div>
</div>
);
};
Or as I understand what you are trying to do, try this
import React, { useEffect, useState } from "react";
import "../styles/Home.css";
import Skills from "../data/Skills";
export const Home = () => {
return (
<div className="home">
<div className="skills">
<h1>Skills</h1>
{Object.keys(Skills).map(skill => <ul key={skill}>
{Skills[skill].map(item => <li key={item.id}>{item.id}</li>)}
</ul>}
</div>
</div>
);
};
Your frontend is a nested array with only one item, so the index is always 0. The following is the fixed version.
import React, { useEffect, useState } from "react";
import "../styles/Home.css";
import Skills from "../data/Skills";
export const Home = () => {
const [skills, setSkills] = useState([]);
useEffect(() => {
setSkills(Skills);
}, []);
const frontend = skills[0].frontend
console.log(frontend);
return (
<div className="home">
<div className="skills">
<h1>Skills</h1>
{frontend.map((item, index) => {
console.log(index)
return <ul key={index}>
<li>{item.id}</li>
</ul>;
})}
</div>
</div>
);
};
It seems your frontend.map((item, index) pointed to nested array, the simplest way was like this if you cannot change your backend result:
frontend[0].map((item, index)
I have a function to populate certain sections of my site with new content on a regular interval (5000), however my function isn't executing when I run the app?
If I set the interval to a console.log function, it works, but it doesn't seem to be working on my 'updateTestimonial' function. If I manually change the idx, it works fine...
I am just learning so apologies if this is obvious -_-
import coverphoto from './img/bkg/moss2.jpg';
import quotes from './img/quotes.png';
import quotes2 from './img/quotes2.png';
import React, { useState, useEffect } from 'react';
const Home = props =>{
const testimonials = [
{
name: 'Ben Frank',
position: 'CEO',
photo: require('./img/chrisphoto.png'),
text:
"Test"
},
{
name: 'Jill Cha',
position: 'Software Engineer',
photo: require('./img/chrisphoto.png'),
text:
'Testimonial1'
},
{
name: 'Adam Niskanen',
position: 'Data Entry',
photo: require('./img/chrisphoto.png'),
text:
"Testimonial2"
},
];
let idx = 0;
let name = testimonials[idx].name;
let position= testimonials[idx].position;
let photo= testimonials[idx].photo;
let text = testimonials[idx].text;
function updateTestimonial() {
idx++;
if (idx > testimonials.length - 1) {
idx = 0;
}
name = testimonials[idx].name;
position= testimonials[idx].position;
photo= testimonials[idx].photo;
text = testimonials[idx].text;
}
setInterval(updateTestimonial, 5000);
return (
<div className="home_main" style={{
backgroundImage: `url(${coverphoto})`,
backgroundRepeat: 'no-repeat'}}>
<div className="home-testimonial-container"><img className="quotes" src={quotes}/><img className="quotes2" src={quotes2}/><div className='testimonial-entry'>
<img className='testimonial-photo'
src={photo}
></img>
<div className='testimonial-text'>
<h3 className='titlestyle2'>{name}</h3><h3 className='subtitlestyle' style={{fontSize: "10pt"}}>{position}</h3></div>
<div className='testimonial-body-container'><h3 className='bodystyle' style={{fontStyle:"italic"}}>{text}</h3>
</div>
</div></div>
</div>
);
}
export default Home;
You need to call setInterval inside a useEffect hook and don't forget to clear the interval when the component unmounts
check the following article https://upmostly.com/tutorials/setinterval-in-react-components-using-hooks
You can do like this
const [idx, setIdx] = useState(0);
useEffect(() => {
const interval = setInterval(() => setIdx((previousValue) => previousValue
+1), 5000);
return () => {
clearInterval(interval);
};
}, []);
I want to delete state data by Id I passed the function as a props. but I am getting error in Ninja.js file saying-
Failed to compile
src\Ninjas.js
Line 11:41: 'deleteNinja' is not defined no-undef
I don't understand why I am getting error.
App.js file-
import Ninjas from './Ninjas';
import React, { useState } from "react";
import AddNinja from './AddNinja';
function App() {
const [ ninjas , setNinja ] = useState([
{ name: 'Pratik', age: 23, belt:'Black', id: 1 },
{ name: 'Yash', age: 20, belt:'Green', id: 2 },
{ name: 'Smit', age: 20, belt:'Pink', id: 3 }
]) ;
const addNinja = (ninja) => {
ninja.id = Math.random();
setNinja([...ninjas , ninja]);
};
const deleteNinja = (id) => {
setNinja(ninjas.filter(ninja => {
return ninja.id !== id
}));
};
return (
<div className="App">
<header className="App-header">
<h1>My First react App</h1>
<Ninjas ninjas = { ninjas } deleteNinja = { deleteNinja } />
<AddNinja addNinja = { addNinja } />
</header>
</div>
);
}
export default App;
Ninja.js file :-
import React from 'react';
const Ninjas = ({ ninjas }) => {
const ninjaList = ninjas.map(ninja => {
return ninja.age > 19 ? (
<div className="ninja" key = { ninja.id }>
<div>Name: { ninja.name }</div>
<div>Age: { ninja.age }</div>
<div>Belt: { ninja.belt }</div>
<button onClick={() => {deleteNinja(ninja.id) }}>Delete Ninja</button>
</div>
)
: null;
})
return(
<div className='ninja-list'>
{ ninjaList }
</div>
)
}
export default Ninjas;
There is no deleteNinja prop in Ninjas component.
Change code like below:
...
const Ninjas = ({ ninjas, deleteNinja }) => {
...
I need help with this bug I've encountered while using big-react-calendar. When dragging an event, the event always moves to the most left column despite where the mouse is. Moving the event to a different time slot from any other view works just okay though. We're using next-js for this project alongside tailwind-css.
Here is a video of what the bug looks like.
Thank you for your help.
In Test Calendar
import "react-big-calendar/lib/css/react-big-calendar.css";
import "react-big-calendar/lib/addons/dragAndDrop/styles.css";
import Router from "next/router";
import React, { useState } from "react";
import Select from "react-select";
import { Calendar, dateFnsLocalizer, Views } from "react-big-calendar";
import withDragAndDrop from "react-big-calendar/lib/addons/dragAndDrop";
import format from "date-fns/format";
import parse from "date-fns/parse";
import startOfWeek from "date-fns/startOfWeek";
import getDay from "date-fns/getDay";
const locales = {
"en-US": require("date-fns/locale/en-US"),
};
const localizer = dateFnsLocalizer({
format,
parse,
startOfWeek,
getDay,
locales,
});
const DragAndDropCalendar = withDragAndDrop(Calendar);
export default function MyCalendar() {
const [events, setEvents] = useState(
[
{
id:1,
title:"help",
start:new Date(),
end: new Date(),
}
]
);
const [showCalendarModal, setShowCalendarModal] = useState(false);
const [selectedDate, setSelectedDate] = useState(undefined);
const [showAssignments, setShowAssignments] = useState(true);
const [showCourseTimes, setShowCourseTimes] = useState(true);
const [showOfficeHours, setShowOfficeHours] = useState(true);
const [showStudySessions, setShowStudySessions] = useState(false); // add later
const setView = [
setShowAssignments,
setShowCourseTimes,
setShowOfficeHours,
setShowStudySessions,
];
const handleSelectSlot = ({ start, end, slots }) => {
//pop modal up, from this and be able to pass through, these slots
setSelectedDate(start);
return;
};
const moveEvent = ({ event, start, end }) => {
const thisEvent = event;
const nextEvents = events.map((existingEvent) => {
return existingEvent.id == event.id
? { ...existingEvent, start, end }
: existingEvent;
});
setEvents(nextEvents);
};
const viewOptions = [
{ value: "Assignments", label: "Assignment due dates", index: 0 },
{ value: "Courses", label: "Courses times", index: 1 },
{ value: "Office Hours", label: "Office hours", index: 2 },
{
value: "Study Sessions",
label: "Study sessions (Not implemented)",
index: 3,
},
];
const filterViewChange = (selected) => {
var indexOfSelected = [];
selected.map((selection) =>
indexOfSelected.push(selection.index)
);
viewOptions.map((option) =>
indexOfSelected.includes(option.index)
? setView[option.index](true)
: setView[option.index](false)
);
};
return (
<div className="h-auto">
<div>
<DragAndDropCalendar
selectable
resizable
popup
localizer={localizer}
events={events}
startAccessor="start"
endAccessor="end"
onEventDrop={moveEvent}
onEventResize={moveEvent}
onSelectEvent={(event) => handleSelectEvent(event)}
onSelectSlot={handleSelectSlot}
style={{ height: 500 }}
defaultDate={new Date()}
/>
<Select
defaultValue={[viewOptions[0], viewOptions[1], viewOptions[2]]}
isMulti
options={viewOptions}
name="View"
onChange={filterViewChange}
/>
</div>
</div>
);
}
// notes
// https://jquense.github.io/react-big-calendar/examples/index.html?ref=creativetim#prop-scrollToTime
//examples
// https://github.com/jyhwng/dashboard/blob/master/src/components/Calendar/FullCalendar.js
// https://demos.creative-tim.com/nextjs-material-dashboard-pro/admin/calendar?_ga=2.137767600.1882045019.1616627454-2002691398.1612228651
// https://www.creative-tim.com/learning-lab/nextjs/react-big-calendar/material-dashboard
// error fixes
// https://github.com/jquense/react-big-calendar/issues/234 // style loaderm
// https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr // no document found, x on ssr or have loading thing.
// https://stackoverflow.com/questions/24647839/referenceerror-document-is-not-defined-in-plain-javascript/24648001
// https://stackoverflow.com/questions/62348977/is-there-a-way-to-disable-resizing-and-dragging-of-events-for-on-specific-views
Page calling TestCalendar
import dynamic from "next/dynamic";
const Calendar = dynamic(() => import("#/components/calendars/TestCalendar"), {
loading: () => <p>Loading...</p>,
ssr: false,
});
export default function Dashboard() {
return <Calendar />;
}
Found out on their gh issue page that this is a bug with ver. 0.33.2. Luckily it's currently being resolved. tiwatson has fixed it (thank you) and is now waited to be merged into master.
Here is the thread that I found the issue and the pull request.
https://github.com/jquense/react-big-calendar/issues/1886
https://github.com/jquense/react-big-calendar/pull/1892
Edit: They merged it! Yay!