Trigger events upwards for custom components - reactjs

I have a custom made component called CoolButton.
If I involve the component in another component like below, I'd somehow like to trigger the onClick-event, just like if it was a normal button.
A second question (not as important), is if it's possible to access the Press Me-value which was passed down the the CoolButton-component, in the child/CoolButton-Component. I'd much rather want Press Me to be dislayed instead of I'm button
export default function Home() {
[timesClicked, setTimesClicked] = useState(0)
return (
<div className="home">
<h1>Click the button!</h1>
<div>The CoolButton has been clicked {timesClicked} times!</div>
<CoolButton onClick={() => setTimesClicked(timesClicked + 1)}>Press Me</CoolButton>
</div>
);
}
export default function CoolButton() {
return (
<div className="cool_button">
<button>I'm button</button>
</div>
);
}

You are passing onClick as a prop to CoolButton component. Unless you use that prop in your component, it would not make any difference. Regarding your second question, if you would like wrap your component around some content, you should provide children in the component. Something like this:
export default function Home() {
[timesClicked, setTimesClicked] = useState(0)
return (
<div className="home">
<h1>Click the button!</h1>
<div>The CoolButton has been clicked {timesClicked} times!</div>
<CoolButton onClick={() => setTimesClicked(timesClicked + 1)}>Press Me</CoolButton>
</div>
);
}
export default function CoolButton(props) {
return (
<div className="cool_button">
<button onClick={props.onClick}>{props.children}</button>
</div>
);
}

You should pass the state variables down to the button and call them on the onClick event of the <button>.
You can pass a custom title to the button as prop as well
export default function Home() {
const [timesClicked, setTimesClicked] = useState(0);
return (
<div className='home'>
<h1>Click the button!</h1>
<div>The CoolButton has been clicked {timesClicked} times!</div>
<CoolButton
setTimesClicked={setTimesClicked}
title='Press Me'
/>
</div>
);
}
export default function CoolButton({ title, setTimesClicked }) {
return (
<div className='cool_button'>
<button onClick={() => setTimesClicked((oldTimes) => oldTimes + 1)}>{title}</button>
</div>
);
}

Related

Add element in array by button click

I have product cards that are rendered based on a json file.
By clicking on the "Add to Cart" button, the element should be added to the array сartList, but this does not happen.
I also tried to forward the function to the component itself, but it didn’t work out too well for me.
Shop.jsx:
import React, { useState } from 'react';
import './Instruments.css';
import Cart from '../components/Cart'
import Product from '../components/Product'
import cart from '../img/cart.png';
import data from "../data/data.json";
unction Shop() {
const [value, setValue] = useState('');
const [currentData, setCurrentData] = useState(data);
const [cartList, setCartList] = useState([]);
return (
<div className='shop'>
<div className='container'>
<div className='shop__main-products'>
{
currentData.filter((el) => {
return value.toLowerCase() === '' ? el : el.title.toLowerCase().includes(value.toLowerCase())
}).map((el, index) => {
return (
<Product img={el.img} title={el.title} price={el.price} key={el.id} onClick={() => setCartList([...cartList, el])}/>
)
})
}
</div>
</div>
<Cart active={modalActive} setActive={modalSetActive}/>
</div>
</div>
);
}
export default Shop;
Product.jsx:
import React, { useState } from 'react';
import './Product.css';
function Product({img, title, price, id, type}) {
return (
<div className='product' key={id} type={type}>
<div className='buy__top'>
<div className='product__top-image-background'>
<img className='product__top-image' src={img}></img>
</div>
<h3 className='product__top-title'>{title}</h3>
</div>
<div className='product__buy'>
<h3 className='product__buy-price'>{price} грн</h3>
<button className='product__buy-button'>В корзину</button>
</div>
</div>
)
}
export default Product;
It looks like the issue is with how you're passing the onClick function to the Product component. The onClick prop should be passed to the "Add to Cart" button, not the Product component itself. You should change the following line:
<Product img={el.img} title={el.title} price={el.price} key={el.id} addToCart={() => setCartList([...cartList, el])}/>
And in the Product component, you should add the onClick prop to the "Add to Cart" button:
<button className='product__buy-button' onClick={addToCart}>В корзину</button>
This way, when the button is clicked, it will call the addToCart function and add the element to the cartList array.
You are not adding the onClick function to the props of the Product component pass it down the pipe and itll work.
function Product({img, title, price, id, type, onClick}) {
return (
<div className='product' key={id} type={type}>
<div className='buy__top'>
<div className='product__top-image-background'>
<img className='product__top-image' src={img}></img>
</div>
<h3 className='product__top-title'>{title}</h3>
</div>
<div className='product__buy'>
<h3 className='product__buy-price'>{price} грн</h3>
<button className='product__buy-button' onClick={onClick}>В корзину</button>
</div>
</div>
)
}

Updating useState from components

I am learning ReactJS (slowly it seems) and was wondering how the below would work:
I have a search function that the user can enter a word(s) into and it spits out a load of variations of the word entered. The word is put into a button that I would like the user to be able to click and have the whole thing happen again (rather than them having to enter the name in manually).
I can't figure out how to update the useState from the NameList.js file. (I currently get the Error: React Hook "useState" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function) Thanks in advance!
NameList.js
export default function NamesList({ namesList }) {
var names_generated = arrayMaker(generator(split_name(namesList.toString())))
return (
names_generated.map(names_generated => {
return(
<div className="col-4 col-xl-2 col-xxl-1">
<button className="sug-names">{names_generated.name}</button>
</div>
)
})
)
}
Home.js
export default function Home() {
const [namesList, setNamesList] = useState([])
const inputName = useRef()
function getInputName(e){
e.preventDefault();
const name = inputName.current.value
if (name === '') return
setNamesList([name])
}
return (
<>
<div className="d-flex align-items-center justify-content-center">
<div className="">
<Container>
<Form>
<div>
<Form.Control ref={inputName} id="input_name" name="username" type="text" placeholder="Desired Name" />
<Button onClick={getInputName} variant="primary" type="submit"></Button>
</div>
</Form>
</Container>
<Container>
<div className='row'>
<NameList namesList={namesList} />
</div>
</Container>
</div>
</div>
<div>0 Names Found</div>
</>
)
}
I guess it happened because of two things,
The first is that the child should not be in the form of:
“function NamesList(){}”
but rather must be in the form of:
“const NamesList =() =>{}”
and as for the parent, it must be in the form of:
“function home(){}”
and not
“const NamesList = () =>{}”
And the second thing is to try to delete the parentheses like this code:
const NamesList = (namesList) => {
var names_generated = arrayMaker(generator(split_name(namesList.toString())))
return (
names_generated.map(names_generated => {
return(
<div className="col-4 col-xl-2 col-xxl-1">
<button className="sug-names">{names_generated.name}</button>
</div>
)
})
)
}
export default NamesList ;
also edit this function in Home file:
function getInputName(e){
e.preventDefault();
const name = inputName.current.value
if (name === '') return
setNamesList(name)
}

How to pass a state (hook) between separated files (components) in React

Btw I already did a lot of research trying to solve this; So far I'm still stuck on this:
This is the first component in file1.jsx:
import * as React from 'react';
export default function MenuPopupState(props){
const [career, setCareer] = React.useState('');
return (
<div>
<button onClick={() => { setCareer(career) }}>
Press me
</button>
</div>
)
}
This is the another component in file2.jsx where I want to use the career state:
import * as React from 'react';
import MenuPopupState from './components/Menupopup';
export default function Header(){
const career = MenuPopupState.career;
return (
<div>
<a key={career.id}>
{career.name}
</a>
</div>
)
}
I tried differents methods, without reaching my goal of use the career.name in the Header
If state is shared between components, then you need to elevate that state to a common parent.
Then you can pass that state down to the children, probably as props or context.
For example:
function App() {
const [career, setCareer] = React.useState('');
return <>
<MenuPopupState career={career} onClick={setCareer} />
<Header career={career} />
</>
}
function MenuPopupState(props){
return (
<div>
<button onClick={() => props.onClick(props.career)}>
Press me
</button>
</div>
)
}
function Header(props){
return (
<div>
<a key={props.career.id}>
{props.career.name}
</a>
</div>
)
}

i`m a React beginner and function setState() is not working, and i need your help guys

I'm currently studying React and tried to make To-do list. Below is the source code.
I want to change the state "display" of the Frame component by clicking the button. I found out that the handler I addEventListener'd to the button element worked, but the state display never changed and even there are no errors on console. Why?
Frame Component
class Frame extends Component {
state = {
list: ["왜", "안돼냐"],
display: "before!!!",
};
registerHandler = () => {
this.setState = {
display: "after",
};
};
render() {
return (
<div className="frame">
<h1>To-Do-Lists</h1>
<h2>{this.state.display}</h2>
<div className="wrapper">
<Lists list={this.state.list} />
</div>
<div className="action">
<Button name="Register" onClick={this.registerHandler} />
</div>
</div>
);
}
}
export default Frame;
Button 관련 부분
import React, { Fragment } from "react";
const button = (props) => {
return (
<Fragment>
<button onClick={props.onClick} className="action button">
{props.name}
</button>
</Fragment>
);
};
export default button;
Mby you trying to set this.setState equal to something, try use it like this this.setState({})

How to get text of multiple clicked elements using useRef?

I'm trying to get useRef to console.log the text of the clicked element but it just logs the last span element of "Green" every time no matter which span element I click.
Is there a way to console.log the text for the clicked element? Perhaps there's a better hook to get the result I'm looking for?
Thanks for any help.
import React, { useRef } from "react";
export default function Hello() {
const ref = useRef(null);
function checkRef() {
console.log(ref.current.innerText);
}
return (
<div className="container">
<span ref={ref} onClick={checkRef} className="selected">
Blue
</span>
<span ref={ref} onClick={checkRef} className="selected">
Red
</span>
<span ref={ref} onClick={checkRef} className="selected">
Green
</span>
</div>
);
}
If you need a ref, put the <span>s into a separate component:
const Button = ({ text }) => {
const ref = useRef(null);
function checkRef() {
console.log(ref.current.innerText);
}
return (
<span onClick={checkRef} className='selected' ref={ref}>
{text}
</span>
);
};
export default function Hello() {
return (
<Button text='Blue' />
<Button text='Red' />
<Button text='Green' />
);
}
Though, at this point, you could also remove the ref completely and just log the text prop. This would be much more elegant if it's possible with your real code:
function checkRef() {
console.log(text);
}

Resources