JSX onClick event seems to be clicked on default - reactjs

I think I am doing something stupid. I have some code and can't figure out why its not working how I expect it to.
I expect the terminal to log to the terminal when the button / link is clicked but it seems to do it regardless
Code below
import React, { Component } from 'react'
import DataExample from './dataExample'
export default class home extends Component {
state = {
name:"Joy",
place:"nirvana"
}
consoleLog = (e) =>{
return console.log("just clicked")
}
render() {
return (
<div>
<h3>This is my homepage that contains components</h3>
<a href="#" onClick={this.consoleLog("link clicked")}>My Button</a>
</div>
)
}
}
Actual result shows the console.log proir to my clicking button

Currently you are calling the this.consoleLog() in the code instead of passing it.
This should work:
<a href="#" onClick={() => this.consoleLog("link clicked")}>My Button</a>

consoleLog() is calling on the render
return (
<div>
<h3>This is my homepage that contains components</h3>
<a href="#" onClick={() => this.consoleLog("link clicked")}>My Button</a>
</div>
)
}

Related

Cannot read properties of null (reading 'children') in React but in Vanilla.js works

I am doing a React App and trying to make a image slider.
I am working in replit.com and in the React App the JS won't work. When I made it in a simple Repl (HTML, CSS and Vanilla.js only) works perfectly.
When I try to do a query select and console log the ul with the className="carousel-track" prop out I get null so it breaks it all.
Carousel component:
import React from 'react';
import Slide from "./Slide";
import Dot from "./Dot"
import "../css/carousel.scss";
// import "../js/carousel.js"
export default function Carousel(props) {
const { players } = props;
const allSlides = players.map(player => {
return <Slide
key={player.key}
name={player.name}
team={player.team}
img={player.img}
/>
});
const allDots = players.map(player => {
return <Dot key={players.indexOf(player)}/>
})
return (
<div className="carousel">
<button className="carousel-btn btn-left">
<i className="fa-solid fa-paper-plane"></i>
</button>
<div className="carousel-track-container">
<ul className="carousel-track">
{allSlides}
</ul>
</div>
<button className="carousel-btn btn-right">
<i className="fa-solid fa-paper-plane"></i>
</button>
<div className="carousel-nav">
{allDots}
</div>
</div>
)
}
And the logic is exactly the same with the one that you can see in the Sources Inspect tab at this link.
If I uncomment that import "../js/carousel" it breaks and nothing is rendered in the page

How Can I conditionally wrap this react component

I am just wondering on how can I avoid duplicating this code when I am conditionally rendering a component.
What I have so far is a navbar component that is connected to redux and it gets state of (isAuth or not) if it's it would render the div with the logout() else it would render the div with login().
Now this approach is not quite good and it's repetitive. I have come across this https://blog.hackages.io/conditionally-wrap-an-element-in-react-a8b9a47fab2 which basically allows you to conditionally render components without duplicating the code but Unfourtnely I was unable to get my head around it. Sorry, I am just learning to react at the moment.
If you please tell me how to use this or if there is an alternative way that i can try that would be very helpfull
Thanks
function Navbar({ isAuth, logOut }) {
if(isAuth) {
return(
<div className="navbar">
<a> link A</a>
<a> link B</a>
<a> link C</a>
<a> link D</a>
<button onClick={() => logOut()} > Logout </button>
</div>
)
}
return (
<div className="navbar">
<a> link A</a>
<a> link B</a>
<a> link C</a>
<a> link D</a>
<button> Login </button>
</div>
)
}
const mapStateToProps = ({ login }) => {
return {
isAuth: login.isAuthenticated
};
};
export default connect(
mapStateToProps,
{ logOut }
)(Navbar);
Just make the button render conditional;
function Navbar({ isAuth, logOut }) {
return(
<div className="navbar">
<a> link A</a>
<a> link B</a>
<a> link C</a>
<a> link D</a>
{isAuth ? <button onClick={() => logOut()} > Logout </button> : <button> Login </button>}
</div>);
}
}
const mapStateToProps = ({ login }) => {
return {
isAuth: login.isAuthenticated
};
};
export default connect(
mapStateToProps,
{ logOut }
)(Navbar);
You can place basic conditions within render/returns wrapped in curly braces - {}. Basically if isAuth is truthy render logout, otherwise login.

How to trigger a function from one component to another component in React.js?

I'am creating React.js Weather project. Currently working on toggle switch which converts celcius to fahrenheit. The celcius count is created in one component whereas toggle button is created in another component. When the toggle button is clicked it must trigger the count and display it. It works fine when both are created in one component, but, I want to trigger the function from another component. How could I do it? Below is the code for reference
CelToFahr.js (Here the count is displayed)
import React, { Component } from 'react'
import CountUp from 'react-countup';
class CeltoFahr extends Component {
state = {
celOn: true
}
render() {
return (
<React.Fragment>
{/* Code for celcius to farenheit */}
<div className="weather">
<div className="figures">
<div className="figuresWrap2">
<div className="mainFigureWrap">
<CountUp
start={!this.state.celOn ? this.props.temp.cel : this.props.temp.fahr}
end={this.state.celOn ? this.props.temp.cel : this.props.temp.fahr}
duration={2}
>
{({ countUpRef, start}) => (
<h1 ref={countUpRef}></h1>
)}
</CountUp>
</div>
</div>
</div>
</div>
{/*End of Code for celcius to farenheit */}
</React.Fragment>
)
}
}
export default CeltoFahr
CelToFahrBtn (Here the toggle button is created)
import React, { Component } from 'react'
import CelToFahr from './CeltoFahr'
class CelToFahrBtn extends Component {
state = {
celOn: true
}
switchCel = () => {
this.setState({ celOn: !this.state.celOn })
}
render = (props) => {
return (
<div className="button" style={{display: 'inline-block'}}>
<div className="weather">
<div className="figures">
<div className="figuresWrap2">
<div className="mainFigureWrap">
<div onClick={this.switchCel} className="CelSwitchWrap">
<div className={"CelSwitch" + (this.state.celOn ? "" : " transition")}>
<h3>C°</h3>
<h3>F°</h3>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default CelToFahrBtn
Here when I click on switchCel it must trigger the celcius to fahrenheit value and vice-versa. How to do it? Any suggestions highly appreciated. Thanks in advance
I would have the celToFahr be the parent component of the celToFahrBtn and then pass the function you want to invoke via props
<CellToFahrBtn callback={yourfunction}/>
What else could you do is having a common parent for these to components where you would again do the execution via props and callbacks
The 3rd option would be having a global state which would carry the function like Redux or Reacts own Context. There again you would get the desired function via props and you would execute it whenever you like. This is the best option if your components are completely separated in both the UI and in source hierarchically, but I don't think this is the case in this case.
https://reactjs.org/docs/context.html
These are pretty much all the options you have
To achieve this you'd need to lift your state up and then pass the state and handlers to the needed components as props.
CeltoFahr & CelToFahrBtn would then become stateless components and would rely on the props that are passed down from TemperatureController
class TemperatureController extends Component {
state = {
celOn: true
}
switchCel = () => {
this.setState({ celOn: !this.state.celOn })
}
render () {
return (
<React.Fragment>
<CeltoFahr celOn={this.state.celOn} switchCel={this.state.switchCel} />
<CelToFahrBtn celOn={this.state.celOn} switchCel={this.state.switchCel}/>
</React.Fragment>
)
}
}
It's probably better explained on the React Docs https://reactjs.org/docs/lifting-state-up.html
See this more simplified example:
import React, {useState} from 'react';
const Display = ({}) => {
const [count, setCount] = useState(0);
return <div>
<span>{count}</span>
<Button countUp={() => setCount(count +1)}></Button>
</div>
}
const Button = ({countUp}) => {
return <button>Count up</button>
}
It's always possible, to just pass down functions from parent components. See Extracting Components for more information.
It's also pretty well described in the "Thinking in React" guidline. Specifically Part 4 and Part 5.
In React you should always try to keep components as dumb as possible. I always start with a functional component instead of a class component (read here why you should).
So therefore I'd turn the button into a function:
import React from 'react';
import CelToFahr from './CeltoFahr';
function CelToFahrBtn(props) {
return (
<div className="button" style={{ display: 'inline-block' }}>
<div className="weather">
<div className="figures">
<div className="figuresWrap2">
<div className="mainFigureWrap">
<div onClick={() => props.switchCel()} className="CelSwitchWrap">
<div
className={'CelSwitch' + (props.celOn ? '' : ' transition')}
>
<h3>C°</h3>
<h3>F°</h3>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
export default CelToFahrBtn;
And you should put the logic in the parent component:
import React, { Component } from 'react';
import CountUp from 'react-countup';
import CelToFahrBtn from './CelToFahrBtn';
class CeltoFahr extends Component {
state = {
celOn: true
};
switchCel = () => {
this.setState({ celOn: !this.state.celOn });
};
render() {
return (
<>
<div className="weather">
<div className="figures">
<div className="figuresWrap2">
<div className="mainFigureWrap">
<CelToFahrBtn switchCel={this.switchCel} celOn={celOn} />
</div>
</div>
</div>
</div>
</>
);
}
}

React - use button for redirect link

I'm new to React so sorry if this is too basic.
I am trying to add a button in my app to redirect it to Spotify.
This is how I'm trying to do it, so far.
class Spotify extends Component {
constructor () {
super()
this.handleClick = this.handleClick.bind(this)
}
handleClick () {
console.log('Success!')
}
render () {
return (
<div className='button__container'>
<button className='button' onClick={this.handleClick}>
Link your Spotify account
</button>
</div>
)
}
}
export default Spotify;
Now, what is the best way of linking the above button to:
I think you're looking for something like this:
class Spotify extends Component {
render () {
return (
<div className='button__container'>
<a className='button' role="button" href="http://someurl.com">
Link your Spotify account
</a>
</div>
)
}
}
export default Spotify;
If your component doesn't require state, consider refactoring the above code into a stateless component like so:
export const Spotify = () => (
<div className='button__container'>
<a className='button' role="button" href="http://someurl.com">
Link your Spotify account
</a>
</div>
);
If you are just trying to display a link, an anchor tag will work just fine. You can add target="_blank" to your anchor tag to have it open in a new tab.

Using constants in React Components

I'm trying to print something to console when a list item is clicked. But the list is defined as a constant outside of the component using it. Obviously the onclick/logItem here is not working. How would you go about this?
Strangely, it logs every list item to the console when the component mounts.
My code:
import React, { Component } from 'react';
const LIST_ITEMS = require('./ListItems.json');
const myList =
LIST_ITEMS.data.Items.map((Item) => (
<li key={Item.id} onClick={logItem(Item.name)}>
{Item.name.toUpperCase()}
</li>
))
;
function logItem(name){
console.log(name);
}
class ItemList extends Component {
render() {
return (
<div id="item-list-wrapper">
<h3>Select an Item</h3>
<ul id="item-list">{myList}</ul>
</div>
);
}
}
export default ItemList;
You have to pass a function to onClick, not the result of calling logItem:
onClick={() => logItem(Item.name)}

Resources