Here is my code -
const [time, setTime] = useState('')
const getRefresh = () => {
pageContext.refreshList()
var today = new Date()
var currentTime = today.getHours() + ':' + today.getMinutes() + ':' + today.getSeconds();
setTime(currentTime)
}
<div className="bttn-layout">
<LastRefreshed getRefresh={time}/>
<Button label="Refresh" onClick={e =>getRefresh()} />
</div>
Here is the code in my 'LastRefreshed' component -
const LastRefreshed = (props) => {
return (
<div>
<p>Last Refreshed: {props.time} </p>
</div>
)
}
export default LastRefreshed;
Ideally, when the refresh button is clicked, it will call the getRefresh function which updates a list on my home page as well as passing the current timestamp to 'time' state. This state is then used by my 'LastRefreshed' function and will therefore show the last refreshed timestamp.
At the moment, the code above is not working. The getRefresh function is definitely being called however I am struggling with getting the time to show in my LastRefreshed component. I am wondering if it's because the state is not properly updating? Any help appreciated!
<div className="bttn-layout">
<LastRefreshed time={time}/>
<Button label="Refresh" onClick={e =>getRefresh()} />
</div>
You should change the props name of LastRefreshed to time.
change
<p>Last Refreshed: {props.time} </p> to <p>Last Refreshed: {props.getRefresh} </p>
or
<LastRefreshed getRefresh={time}/> to <LastRefreshed time={time}/>
The name of your prop parameter does not match the name used in the component
<LastRefreshed time={time}/>
Code:-
const [time, setTime] = useState('');
const getRefresh = () => {
pageContext.refreshList();
var today = new Date();
var currentTime = today.getHours() + ':' + today.getMinutes() + ':' + today.getSeconds();
setTime(currentTime);
}
<div className="bttn-layout">
// component property should be `time` instead of `getRefresh`
<LastRefreshed time={time}/>
//Note:- As you are not passing any arguments, directly mention getRefresh function
<Button label="Refresh" onClick={getRefresh} />
</div>
LastRefreshedComponent:-
Note:- Here followed the shorthand syntax of arrow function,
// Also used object destructuring for the props
const LastRefreshed = ({time}) =>
<div>
<p>Last Refreshed: {time} </p>
</div>;
export default LastRefreshed;
Related
i use usestate to create saveImages and setSaveImages, this initial as array, i want to each time i call the function, the content is different, so each time must to push to the array that info, but instead of do push, only replace the 1 position of array, doesnt add new position with different info. I don't know if I explain myself
const galery = useSelector((state) => state.search);
const dispatch = useDispatch();
const [saveImages, setSaveImages] = useState([]);
function savePhoto(e) {
e.preventDefault();
const { target } = e;
const content = target.photo.src;
setSaveImages(content)
console.log(content)
localStorage.setItem("img", saveImages);
dispatch(actionAddFavorite(content));
}
return(
<section className="w-full gap-0 sm:columns-2 md:columns-3 xl:columns-4 2xl:columns-5 3xl:columns-6">
{galery.map((item, index) => {
return (
<form onSubmit={savePhoto} key={index} className="relative">
<button className="bg-gray absolute left-5 top-3 shadow-md">
Guardar
</button>
<img
name="photo"
className="object-cover p-2"
src={item.urls.regular}
alt={item.alt_description}
/>
</form>
);
})}
</section>
)
You set your saveImages to contain "content", but what you want is to add "content" to existing saveImages array. Here is how you can do this:
setSaveImages(oldImages => {
return [...oldImages, content];
});
And here you can learn everything you need to know about state in react
So I have this function here:
const printCardList = (arr) => {
const uo_list = document.getElementById("verify_list");
arr.forEach((card) => {
let list_item = document.createElement("LI");
let str = card.name + " " + card.mana_cost + " " + card.set_name;
list_item.appendChild(document.createTextNode(str));
uo_list.appendChild(list_item);
});
};
and its suppose to insert list items into and unorder list from an array of card objects.
return(
<div className="list-confirm">
<h3> Please confirm card list </h3>
<ul id="verify_list"></ul>
<br />
<button onClick={getCardList}>Confirm</button>
</div>
);
If I do a console.log on arr I can verify that it is an array of cards, but if I console.log card from inside the for each it does not even trigger. It's like the for each does not run. Does anyone have an idea why this is happening?
I'm not sure what you are trying to do, the first part of your code is plain javascript that manipulates the DOM, while the second part is react js object.
You normally don't want to mix these two, either you code your javascript as part of the html, like the first part, or - if you want to create an array of cards in react you can do something like:
let cardList = arr.map(card => {
listItem = <li>{card.name + " " + card.mana_cost + " " + card.set_name }</li>
return listItem;
})
return(
<div className="list-confirm">
<h3> Please confirm card list </h3>
<ul id="verify_list">{cardList}</ul>
<br />
<button onClick={getCardList}>Confirm</button>
</div>
);
what I did is assigned the list itself to a variable named 'cardList', JSX object are just javascript objects, so you can assign them to a variable or return then from a function.
to place the card list inside the page (or component), you can just use the {} notation, which will embed the cardList object as part of the returned JSX object.
Thanks for all the advice. In hindsight, I should have stuck to what I was learning and not try to freestyle. React is about using states. So rather than having a function that will generate HTML from an array of data and I had to do use "the state". Then code the render to loop through the list of cards when the button is pressed.
const [state, setState] = useState([]);
const card_list= ()=> {...}
const changeState = ()=> {setState(card_list)}
return(
<div className="list-confirm">
<h3> Please confirm card list </h3>
<ul>
{state.map((card) => (
<li>{card.name}</li>
))}
</ul>
<br />
<button onClick={changeSate}>Confirm</button>
</div>
);
You should change the onClick. More precisely call the method after getting items from getCardList() method.
This is an example:
const printCardList = (arr) => {
const uo_list = document.getElementById("verify_list");
arr.forEach((card) => {
let list_item = document.createElement("li");
let str = card.name + " " + card.mana_cost + " " + card.set_name;
list_item.appendChild(document.createTextNode(str));
uo_list.appendChild(list_item);
});
};
// this is a test method. Not the real one
const getCardList = () => {
return [ { name: "Card", mana_cost: 0, set_name: "Set: Card" } ];
};
<div className="list-confirm">
<h3> Please confirm card list </h3>
<ul id="verify_list"></ul>
<br />
<button onClick="printCardList(getCardList())">Confirm</button>
</div>
Currently, I am making a calendar in React.js with Moment.js
and I also tried to add some buttons which I can go back and forth for
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/0.14.7/react-dom.min.js"></script>
import './App.css';
import React,{useState} from 'react';
import moment from 'moment';
function App() {
const [getMoment,setMoment] = useState(moment());
const today = getMoment;
const firstWeek = today.clone().startOf('month').week();
const lastWeek = today.clone().endOf('month').week() === 1 ? 53 : today.clone().endOf('month').week();
const calendarArr=()=>{
let result=[];
let week=firstWeek;
for(week; week <=lastWeek; week++){
result =result.concat(
<tr key={week}>
{
Array(7).fill(0).map((data, index) => {
let days = today.clone().startOf('year').week(week).startOf('week').add(index, 'day');
if(moment().format('YYYYMMDD') === days.format('YYYYMMDD')){
return(
<td key={index} className="today" >
<span>{days.format('D')}</span>
</td>
);
}else if(days.format('MM') !== today.format('MM')){
return(
<td key={index} className="other" >
<span>{days.format('D')}</span>
</td>
);
}else{
return(
<td key={index} >
<span>{days.format('D')}</span>
</td>
);
}
})
}
</tr>);
}
return result;
}
return(
<>
<div className="calendar-layout">
<div className="calendar">
<div className="control nav">
<span>{today.format('YYYY MM ')}</span>
<button onClick={()=>{setMoment(getMoment.clone().subtract(1, 'month'))}}> previous month</button>
<button onClick={()=>{setMoment(getMoment.toDate())}}>this month</button>
<button onClick={()=>{setMoment(getMoment.clone().add(1, 'month'))}} >next month</button>
</div>
<table>
<tbody>
{calendarArr()}
</tbody>
</table>
</div>
</div>
</>
)
}
export default App;
months.
previous month and next month buttons are okay, but this month button doesn't work somehow and return this error:TypeError: today.clone is not a function
can you explain what is wrong with my code and how to solve it?
thx!
It is happening because you are converting the moment object to a date object when you do getMoment.toDate()(check this). Since you are changing the state using setMoment, the page is re-rendered which in-turn calls const firstWeek = today.clone() (line number 3 of the App function component)and since today is a Date object, which does not have a clone function, the error is thrown.
You could use the below code to set the moment back to the current time.
<button onClick={()=>{setMoment(moment())}}>this month</button>
I have set up a conditional element on click on a button I've made within react. but default prop runs onload without clicking the button how can I fix this issue?
the button looks like this:
<p onClick={Butter + Milk + Bread + Soup + Cheese > 0 ? props.next_ClickHandler : alert('Please Input some food!')}>Buy Now!</p>
I would like it so that if the values add to greater than 0 the props are passed but if not an alert is played why it this not working as intended?
Edit full code:
import React, { useState, useEffect, useContext } from "react";
import Data from '../shoppingData/Ingredients';
import { quantitiesContext } from '../shoppingData/Quantities';
const ShoppingPageOne = (props) => {
//element displays
const [pageone_show, setPageone_show] = useState("pageOne");
//stores quantities of items as JSON objects
const [Quantities, setQuantities] = useContext(quantitiesContext);
const quantities = useContext(quantitiesContext);
const Bread = quantities[0].Bread.quantities;
const Milk = quantities[0].Milk.quantities;
const Cheese = quantities[0].Cheese.quantities;
const Soup = quantities[0].Soup.quantities;
const Butter = quantities[0].Butter.quantities;
useEffect(() => {
//sets info text using Json
if (props.showOne) {
setPageone_show("pageOne");
} else {
setPageone_show("pageOne hide");
}
}, [props.showOne]);
return (
<div className={"Shopping_Content " + pageone_show}>
<div className="Shopping_input_aligner">
<div className='Shopping_input_container'>
{Data.map((Ingredients) => {
//updates Quanties Hook
const handleChange = (event) => {
setQuantities({
...Quantities,
[Ingredients.Name]: {
...(Quantities[Ingredients.Name] ?? {}),
quantities: event.target.value
}
});
};
return (<div className={"Shopping_input " + Ingredients.Name} key={Ingredients.Name}>
<p>{Ingredients.Name} £{Ingredients.Price}</p>
<input onChange={handleChange.bind(this)} min="0" placeholder="Input food quantity" type="number"></input>
</div>)
})}
</div>
<div className='Discount_list'>
<h3>Discounts:</h3>
<li>Buy one cheese get one free!</li>
<li>Buy a Soup get a half price bread!</li>
<li>A third off butter!</li>
</div>
</div>
<div className="Shopping_Buttons">
<p onClick={() => {Butter + Milk + Bread + Soup + Cheese > 0 ? props.next_ClickHandler : alert('Please Input some food!')}} >Buy Now!</p>
</div>
</div>
);
};
export default ShoppingPageOne;
You can have a cleaner code with something like this if you're using React Hooks
const [ingredientsGreaterThanZero, setIngredientsGreaterThanZero] = useState(false);
useEffect(() => {
if (butter + milk + bread + soup + cheese > 0) {
setIngredientsGreaterThanZero(true)
} else {
setIngredientsGreaterThanZero(false)
}
}, [butter, milk, bread, soup, cheese]);
...
{ingredientsGreaterThanZero ?
<p onClick={props.next_ClickHandler}>Buy Now!</p> :
<p onClick={() => alert('Please Input some food!')}>Buy Now!</p>
}
<p onClick={() => { Butter + Milk + Bread + Soup + Cheese > 0 ? props.next_ClickHandler : alert('Please Input some food!')}}>Buy Now!</p>
Can you try using this?
Reason
If you attach any event in element with onClick() or any other event handler,
You shouldn't add any function invocation like in your example alert().
Because, of parentheses () the function runs when component mounted in dom.
Example:
<p onClick={alert('runs on load')}>wrong way</p>
Solution
You have to add an empty function and and writes your codes in it. If your codes contain function invocation ( with parentheses () ).
Example:
<p onClick={() => alert ('only runs on click')}>right way</p>
Happy Coding :)
This question already has answers here:
Correct modification of state arrays in React.js
(19 answers)
Closed 3 years ago.
I am trying to build a React app where i can input my weight and height and it will count value of my BMI and show it on a diagram. I did not want to make everything in one component so i divided it into small components.
Here is the main App Component:
const App_function = () => {
const [arrayBMI, setArrayBMI]=useState([]);
const [dateArray, setDateArray]=useState([]);
const handlerMain = (heightData, weightData) => {
const valueOfBMI = weightData / (heightData/100*heightData/100);
console.log(valueOfBMI);
const repMainArray = arrayBMI;
repMainArray.push(valueOfBMI);
setArrayBMI(repMainArray);
const repDateArray = dateArray;
let currentDateData = new Date();
let day = currentDateData.getDate();
if(day < 10) {
day = '0' + day;
}
let month = currentDateData.getMonth() + 1;
if(month < 10) {
month = '0' + month;
}
let year = currentDateData.getFullYear();
let date = `${day}-${month}-${year}`;
repDateArray.push(date);
setDateArray(repDateArray);
}
return (
<div>
<Data handlerFunction={handlerMain}/>
<Diagram arrayMain={arrayBMI} arrayOfDate={dateArray}/>
<div>{arrayBMI[0]} a {arrayBMI[1]}</div>
<StoragE/>
</div>
);
}
And here is the Data Component:
function data_function(props) {
function formCloser(event) {
event.preventDefault();
let heightField = event.target.querySelector('#height').value;
let weightField = event.target.querySelector('#weight').value;
props.handlerFunction(heightField, weightField);
event.target.querySelector('#height').value='';
event.target.querySelector('#weight').value='';
}
return (
<div className="main-div">
<p className="paragraph-boy">BMI Calculator</p>
<form onSubmit={formCloser}>
<div className="inputs">
<div className="input_fields">
<label htmlFor="weight">Weight (in kg)</label>
<input type="text" id="weight" placeholder="50" autoComplete="off"></input>
</div>
<div className="input_fields">
<label htmlFor="height">Height (in cm)</label>
<input type="text" id="height" placeholder="175" autoComplete="off"></input>
</div>
</div>
<button type="submit" className="btn">Calculate BMI</button>
</form>
</div>
);
}
export default data_function;
As you can see App Component is the parent of Data Component. Whenever I fill out the form and hit submit, it triggers handlerFunction which passes the data from
the Data Component to the App Component. The data which was sent to App Component is used to calculate the BMI and then the value of it is pushed into arrayBMI (which is a state in App Component). I don't understand why after submitting it does not re-render the App Component.
Last 2 days i was probably trying to fix the problem which was caused by it. Today i discovered that my main App Component does not re-render when the value of any of the state changes and i have not idea why.
Replace this code
const repMainArray = arrayBMI;
repMainArray.push(valueOfBMI);
by
const repMainArray = [...this.sate.arrayBMI,valueOfBMI] ;
and
const repDateArray.push(date);
Wrap your main handler function in https://reactjs.org/docs/hooks-reference.html#usecallback to have dependencies (listeners for changes).