I'm doing a broker simulator and I need to pass the data (side,price,volume,timestamp) into different tab, which is like grandparent's brother. The problem is I have no idea, how to transport data that far
Modalbuy.js
import React from "react";
import "./modal.css";
const Modalbuy = ({active, setActive,price}) => {
return (
<div className={active ? "modal active" : "modal"} onClick={() => setActive(false)}>
<div className="modal__content" onClick={e => e.stopPropagation()}>
<header>Make order</header>
<p>BUY {price}</p>
<input placeholder="Volume">{volume}</input>
<div>
<button onClick={() =>{this.props.addData("BUY", price, volume,)}}>Ok</button>
<button>Cancel</button>
</div>
</div>
</div>
)
}
export default Modalbuy;
Select.js
import React, {useState} from "react";
import './select.css'
import Modalbuy from "../popup/Modalbuy"
import Modalsell from "../popup/Modalsell"
import { useEffect } from "react";
const Select = () => {
const [value, setValue] = useState("");
const [usdrub, setUsdrub] = useState(Math.random() * (64-61) + 61);
useEffect(() => {
const interval = setInterval(() => {
setUsdrub(Math.random() * (64-61) + 61);
}, 10000);
return () => clearInterval(interval);
}, [])
const [rubusd, setRubusd] = useState(Math.random() * 2);
useEffect(() => {
const interval = setInterval(() => {
setRubusd(Math.random() * 2);
}, 10000);
return () => clearInterval(interval);
}, [])
function changeSelect(event) {
setValue(event.target.value)
}
const [modalBuyActive, setModalBuyActive] = useState(false)
const [modalSellActive, setModalSellActive] = useState(false)
function addData(side, price, volume, timestamp) {
this.setState({side:side, price:price, volume:volume, timestamp:timestamp})
}
return (
<div>
<select value = {value} onChange={changeSelect}>
<option>Choose instrument</option>
<option name="USD/RUB" value={usdrub}>USD/RUB</option>
<option name="RUB/USD" value={rubusd}>RUB/USD</option>
</select>
<div className="Curr">
<div className="Buy" name="buy"> <button className="Buy" type="btn" onClick={() => setModalBuyActive(true)}>BUY {value + 1} </button>
</div>
<div className="Sell" name="sell"><button className="Sell" type="btn" onClick={() => setModalSellActive(true)}>SELL {value}</button></div>
</div>
<Modalbuy active={modalBuyActive} setActive={setModalBuyActive} price={value + 1} addData={addData}/>
<Modalsell active={modalSellActive} setActive={setModalSellActive} price={value}/>
</div>
)
}
export default Select
Trading.js
import React from "react";
import Timer from "./Timer";
import Select from "./select_curr/Select";
const Trading = () => {
return (
<div>
<Timer/>
<Select/>
</div>
)
}
export default Trading;
Page.js
import React from 'react'
import { Tabs, TabList, TabPanel, Tab } from 'react-re-super-tabs'
import CustomTab from './customTab'
import Trading from '../trading/Trading.js'
import Table from '../archive/table'
const Page = () => {
return (
<div>
<Tabs activeTab='about'>
<TabList>
<Tab component={CustomTab} label='Trading' id='trading' />
<Tab component={CustomTab} label='Archive' id='archive' />
</TabList>
<TabList>
<TabPanel component={Trading} id='trading' />
<TabPanel component={Table} id='table' />
</TabList>
</Tabs>
</div>
)
}
export default Page;
So I need to make a table in Table.js and import there data I got from module dialogue
To summarize the way I understand your problem, The component Modalbuy need to share data with your component Table.
Here are some way I can advise you.
1. The common Parent manage the state
const Page = () => {
const [yourData, setYourData] = useState([])
return (
[...]
<TabPanel component={props=>(<Trading {...props} value={yourData} onChange={setYourData} />)} id='trading' />
<TabPanel component={props=>(<Table {...props} value={yourData} onChange={setYourData} />)} id='table' />
[...]
)
}
This implies intermediate component are in charge to follow those new props to Modalbuy
2. Using Redux librairy
Redux is basicly a librairy to help you to define a global state for your app. You define actions your components can call to transform this global state. On the other way, components can subscribe to that state to be refreshed when a change happen.
Don't hesitate to have a look to tutorials https://react-redux.js.org/tutorials/quick-start
3. Using React Context
export const YourDataContext = React.createContext({})
const Page = () => {
const [yourData, setYourData] = useState([])
return (
<YourDataContext.Provider value={{yourData, setYourData}}>
[...]
</YourDataContext.Provider>
)
}
const Modalbuy = ({active, setActive,price}) => {
const { yourData, setYourData } = React.useContext(YourDataContext)
[...]
})
You define a context YourDataContext. You share a value to this context, here we create a state and passing the getter/setter. All child of the Provider can access the attribute value with the hook React.useContext(YourDataContext)
Related
I am new to React and using React 18 in this app. My problem is that if I click one button inside a map function, it reflects information about all the items. I want only that item information to show for which I clicked the button. The isShown === true part in the CountryInfo.js file is what should reflect only one item; currently clicking the show button shows all item information on the UI (I don't want this to happen). How do I do this?
Visually, this is my UI,
If you see the image above, clicking any show button returns all countries information, which should not happen.
Below is my code:
App.js
import { useState, useEffect } from 'react';
import axios from "axios";
import CountryInfo from './components/CountryInfo';
const App = () => {
const [countries, setCountries] = useState([]);
const [searchCountry, setSearchCountry] = useState("");
const handleCountryChange = event => {
setSearchCountry(event.target.value);
}
const getAllCountriesData = () => {
axios.get("https://restcountries.com/v3.1/all")
.then(response => {
setCountries(response.data);
})
}
useEffect(() => {
getAllCountriesData();
}, []);
return (
<>
<h2>Data for countries</h2>
find countries:
<input value={searchCountry} onChange={handleCountryChange} />
{searchCountry.length > 0 && <CountryInfo countries={countries} searchCountry={searchCountry} />}
</>
)
}
export default App;
CountryInfo.js
import React from "react";
import { useState } from "react";
const CountryInfo = ({ countries, searchCountry }) => {
const [isShown, setIsShown] = useState(false);
let filteredList = countries.filter(country =>
country.name.common.toLowerCase().includes(searchCountry.toLowerCase()));
const handleClick = () => {
setIsShown(true);
}
if (filteredList.length > 10) {
return <div>Too many matches, specify another filter</div>
}
else {
return filteredList.map(country => {
return (
<>
<div key={country.name.common}>
{!isShown &&
<div>
{country.name.common}
<button type="submit" onClick={handleClick}>show</button>
</div>
}
{isShown &&
<div key={country.name.common}>
<h2>{country.name.common}</h2>
<p>
Capital: {country.capital}
{'\n'}
Area: {country.area}
</p>
Languages:
<ul>
{
Object.values(country.languages)
.map((language, index) => <li key={index}>{language}</li>)
}
</ul>
<img src={country.flags.png} alt={`${country.name.common} flag`} height={150} />
</div>
}
</div>
</>
)
})
}
}
export default CountryInfo;
I have a simple Quiz app that fetches the questions from an API (https://opentdb.com/api.php?amount=100), filters them by difficulty, and renders the questions in the 'Questions' component.
I want to hide the settings after filtering - when the questions are shown.
This is my code:
import React, { useEffect, useState } from "react";
import Questions from "./Questions";
const Welcome = () => {
/*Fetch questions*/
const questionsAPI = "https://opentdb.com/api.php?amount=100";
const [questionsFromAPI, setQuestionsFromAPI] = useState([]);
const [difficultyValue, setDifficulty] = useState("");
const [filteredQ, setFilteredQ] = useState([]);
const handleDifficultyChange = (event) => {
setDifficulty(event.target.value);
};
const handleSearchReset = () => {
setDifficulty("");
};
const fetchData = () => {
return fetch(questionsAPI)
.then((response) => response.json())
.then((data) => setQuestionsFromAPI(data.results));
};
useEffect(() => {
fetchData();
}, []);
useEffect(() => {
setFilteredQ(
questionsFromAPI.filter((q) => q.difficulty === difficultyValue)
);
}, [questionsFromAPI, difficultyValue]);
return (
<div>
<h1>QUIZ</h1>
**<div classname="setting">
<h1>Search Posts</h1>
<br />
<p>difficulty</p>
<input
type="string"
min={"difficulty"}
value={difficultyValue}
onChange={handleDifficultyChange}
/>
<br />
<button classname="button" type="button" onClick={handleSearchReset}>
Reset Search
</button>
</div>**
{filteredQ.length > 0 ? (
<div>
<Questions questionsAPI={filteredQ}></Questions>
</div>
) : (
<br></br>
)}
</div>
);
};
export default Welcome;
In React elements have the attribute hidden, you can use that to hide your settings div. For example by using a hook:
const [isHidden, hideSettings] = useState(false)
And to the settings div add the following
<div hidden={isHidden} classname="setting">
and use hideSettings(true) after filtering
I want to fetch the data when the button is clicked but the Newsitem component is running first and then updating the value of data_grabber. That means it is displaying the defalut values rather than the data that I fetched from the newsapi. After displaying the newsitem component with default values, data_grabber is updating the fetched data.
What can be the solution?
App.js
function App() {
const [input_data, setInput_data] = useState("");
const [btn_data, setBtn_data] = useState("");
const [data_grabber, setData_grabber] = useState([]);
return (
<>
<Navbar
input_data={input_data}
setInput_data={setInput_data}
setBtn_data={setBtn_data}
btn_data={btn_data}
data_grabber={data_grabber}
setData_grabber={setData_grabber}
/>
{data_grabber? data_grabber.map((news_data)=>{
return(
<NewsItem news_data={news_data}/>
)
}):<div>No data available</div>}
</>
);
}
export default App;
Navbar.js
import { useEffect } from "react";
export default function Navbar(props) {
const onClicker = async (e) => {
e.preventDefault();
props.setBtn_data(props.input_data);
};
useEffect(() => {
const fetcher = async () => {
const link = `https://newsapi.org/v2/everything?q=${props.btn_data}&apiKey=API_KEY`;
const raw_data = await fetch(link);
const data = await raw_data.json();
console.log(data);
props.setData_grabber(data.articles)
};
fetcher();
}, [props.btn_data]);
return (
<div>
<form className="d-flex">
<input
onChange={(e) => props.setInput_data(e.target.value)}
value={props.input_data}
className="form-control me-2"
type="search"
placeholder="Search"
aria-label="Search"
/>
<button
className="btn btn-outline-success"
type="submit"
onClick={onClicker}
>
Search
</button>
</form>
</div>
NewsItem.js
import React, { Component } from "react";
export default class NewsItem extends Component {
render() {
const {title, description, url, urlToImage} = this.props.data
const defaultImage = `https://blogger.googleusercontent.com/img/a/AVvXsEh20SgNNsDlKyWWmB7XgB5SfFY10M6CqJAq93HwGtssTn2cWz6w9zHPjXf91WwoWr27QeaC4HsGv2NxPOXUdvk6xodUojnw8rUuAkEMY3Qb4ucoVpN3nSyF8JW_xVDWa2aSMEWH387hPsfouSJyClLNburIcDbXIeJamuTHwiSvw4hdNnqeeICcvg1wrQ=w1200-h630-p-k-no-nu`
return (
<div>
<div className="card">
<img src={urlToImage?urlToImage:defaultImage} className="card-img-top" alt="..." />
<div className="card-body">
<h5 className="card-title">{title?title:'No title available'}</h5>
<p className="card-text">
{description?description.slice(0, 50):"no description available"}...
</p>
<a href={url} target="_blank" rel="noreferrer"className="btn btn-primary">
read more
</a>
</div>
</div>
</div>
);
}
}
One fix could be to
make a variable of the updated state:
in the UseEffect ,
add :
const updated = data.articles
props.setData_grabber(updated)
Check whether data_grabber array is empty or not and then do the rendering inside App component as follows.
{
data_grabber.length > 0 ? (
data_grabber.map((news_data) => {
return <NewsItem news_data={news_data} />;
})
) : (
<div>No data available</div>
);
}
{ data_grabber !== undefined && data_grabber.length > 0 ? data_grabber.map((news_data)=>{
return(
<NewsItem news_data={news_data}/>
)
}):<div>No data available</div>}
Check data_grabber is undefined or empty.
Then, fix NewsItem props.data like this.
export default class NewsItem extends Component {
render() {
const {title, description, url, urlToImage} = this.props.news_data
also fix here in useEffect
useEffect(() => {
const fetcher = async () => {
const link = `https://newsapi.org/v2/everything?q=${props.btn_data}&apiKey=c990aa0235da4635997afd1f7459860c`;
const raw_data = await fetch(link);
const data = await raw_data.json();
console.log(data);
if(data.articles){
props.setData_grabber(data.articles)
}
};
fetcher();
I'm trying to simply pass the Id of a clicked item to display on another page under a different component ("Cart") . At the bottom of the code below, I have a button containing <Cart test={product.id} /> which extracts the Id that I want to be displayed in "Cart" when the button is clicked.
However, I am instead getting an error message of:
Objects are not valid as a React child (found: object with keys
{history, location, match, staticContext}). If you meant to render a
collection of children, use an array instead.
Is there a simple syntax error?
import React, { useState, useEffect, Cart } from 'react';
import './../App.css';
import * as ReactBootStrap from 'react-bootstrap';
function Item(props) {
const [product, setProduct] = useState([]);
const [loading, setLoading] = useState(false);
const [quantity, setQuantity] = useState(1);
const [cost, setCost] = useState([]);
useEffect(async () => {
fetchItems();
}, []);
const itemId = props.match.params.item;
const fetchItems = async () => {
const data = await fetch('https://fakestoreapi.com/products/' + itemId);
const items = await data.json();
setProduct(items);
setLoading(true);
setCost(items.price);
};
function priceUSD(change) {
return change.toFixed(2);
}
useEffect(() => {
const newCost = quantity * product.price;
setCost(priceUSD(newCost));
}, [quantity]);
return (
<div className="App">
<h2>Item</h2>
<div className="gridContainer">
{loading ? (
<div key={itemId} className="productStyle">
<img src={product.image} className="productImage"></img>
<p>{product.title}</p>
<p>{product.description}}</p>
<p>${priceUSD(product.price)}</p>
<div className="quantity">
<button
className="btn minus-btn"
type="button"
onClick={quantity > 1 ? () => setQuantity(quantity - 1) : null}
>
-
</button>
<input type="text" id="quantity" value={quantity} />
<button className="btn plus-btn" type="button" onClick={() => setQuantity(quantity + 1)}>
+
</button>
</div>
<button type="button" onClick={() => <Cart test={product.id} />}>
Add to shopping cart ${cost}
</button>
</div>
) : (
<ReactBootStrap.Spinner className="spinner" animation="border" />
)}
</div>
</div>
);
}
export default Item;
Cart
import React, { useState, Item } from 'react';
import './../App.css';
import './Item.js';
function Cart(test) {
return (
<div className="App">
<p>{test}</p>
</div>
);
}
export default Cart;
Component props are objects. You can read more about them in the official documentation.
You can either destructure the props of the Cart component:
function Cart({test}) {
return (
<div className="App">
<p>{test}</p>
</div>
);
}
or use explicitly test property of props:
function Cart(props) {
return (
<div className="App">
<p>{props.test}</p>
</div>
);
}
I write a React.js note web application where a user can add up to 10 notes.
I use map() to iterate the array of notes, and a useState(1) hook to update its count (the default number of notes is 1), so I would like to do something like this:
{[...Array(noteCount)].map((_, i) => <Note onUpdateNoteCount={() =>setNoteCount(n => n - 1)} key={i} />)}
The thing is that the Note() component is inside a Main() component which is in the App() component, so I want to get the needed values as props of App(), and than use them in Note(), but can not figure out how and where to put it.
Thanks!
App.js
import React from 'react';
import Header from './Header';
import Main from './Main';
function App () {
const [noteCount, setNoteCount] = React.useState(1);
function multiplyNoteComponent () {
if (noteCount < 20) {
setNoteCount(n => n + 1)
}
else {
alert('too many notes. remove or combine some of them together!')
}
}
return (
<div>
<Header/>
{[...Array(noteCount)].map((_, i) => <Main onUpdateNoteCount={() =>setNoteCount(n => n - 1)} key={i} />)}
<button
style={{left: '5%'}}
id='addNoteBtn'
onClick={multiplyNoteComponent}
title='Add a note'
>
+
</button>
</div>
);
}
export default App;
Main.js
import React from 'react';
import Note from './Note';
function Main () {
return (
<main>
your notes are:
<Note/>
</main>
)
}
export default Main;
Note.js
import React from 'react';
function Note () {
return (
<div> <button title='delete note' onClick={}>X</delete>
<li>
<input type='text'/>
</li>
</div>
)
}
export default Note
Edit: the reason I think I need the setNoteCount() function to be used in the Note() component, is for the count down when a note is being deleted (every note has its own delete button).
I would recommend this architecture of the your App.
Store the Notes array at the App level.
Add a note using NoteInput which adds a notes to your Notes array.
Map your Notes using the Note component which takes onDelete as a prop from App level.
Your App component should be responsible for storing and delete a note from the state.
In your example, notesCount is meant to a derivative state.
i.e it could be derived simply from the Notes array (notes.length).
So, rather than storing notesCount, I recommend storing notes and deriving count from it.
You could see the working example here :- https://stackblitz.com/edit/react-g19tei
import React from "react";
import "./style.css";
const NOTES_ALLOWED = 10;
export default function App() {
const [notes, setNotes] = React.useState([]);
function addNote(newNote) {
if (notes.length === NOTES_ALLOWED) {
alert(`Only ${NOTES_ALLOWED} notes are allowed to be added`)
} else {
setNotes([...notes, newNote]);
}
}
function handleDelete(deleteNoteIdx) {
const newNotes = [...notes];
// delete the note at the specific index
newNotes.splice(deleteNoteIdx, 1)
setNotes(newNotes);
}
return (
<div>
<div style={{ marginTop: 20, marginBottom: 20 }}>
<p>Your notes are</p>
{notes.map((note, idx) => (
<Note
note={note}
onDelete={() => handleDelete(idx)}
/>
))}
</div>
<NoteInput onAdd={addNote} />
</div>
);
}
function Note({ note, onDelete }) {
return (
<div>
<p>{note}
<button onClick={onDelete}>Delete Note</button>
</p>
</div>
)
}
function NoteInput({ onAdd }) {
const [note, setNote] = React.useState('');
function handleSubmit(e) {
e.preventDefault();
const noteToBeSend = note;
setNote('')
onAdd(noteToBeSend.trim());
}
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
value={note}
onChange={e => setNote(e.target.value)}
required
/>
<button type="submit">Add Note</button>
</form>
</div>
)
}