This question already has answers here:
Why is my onClick being called on render? - React.js
(5 answers)
Closed 2 years ago.
Hi I am building a frontend in react and I am rendering a List of places that I get from google maps api. I want each place to fire an action on onClick. If I don't pass any value it works, if I pass the id of the place that I get from props than onClick is fired when the list item is rendered leading to an error.
Here is the list component
import {ListGroup} from "react-bootstrap";
import {useDispatch} from "react-redux";
import {selectedPlace} from "../../actions/searchActions";
const PlaceList=function (props) {
const dispatch=useDispatch()
const handleClick=function (id) {
console.log('ciao '+id)
}
return(
<ListGroup>
{props.places.map(item=>{
return (<ListGroup.Item variant="flush" onClick={handleClick(item['place_id'])}>{item['formatted_address']}</ListGroup.Item>)
})}
</ListGroup>
)
}
export default PlaceList
I want the onClick to be fired just when the list item is clicked. Any Idea on how to solve?
onClick functions should be called like this!
import { ListGroup } from "react-bootstrap";
import { useDispatch } from "react-redux";
import { selectedPlace } from "../../actions/searchActions";
const PlaceList = (props) => {
const dispatch = useDispatch();
const handleClick = (id) => {
console.log('ciao ' + id)
}
return (
<ListGroup>
{
props.places.map(item => {
return (<ListGroup.Item variant="flush" onClick={() => handleClick(item['place_id'])}>{item['formatted_address']}</ListGroup.Item>)
})
}
</ListGroup>
)
}
export default PlaceList
Your onClick should be calling the function like this:
import { ListGroup } from 'react-bootstrap';
import { useDispatch } from 'react-redux';
import { selectedPlace } from '../../actions/searchActions';
export default (props) => {
const dispatch = useDispatch();
const handleClick = (id) => {
console.log('ciao ' + id);
};
return (
<ListGroup>
{props.places.map((item) => (
<ListGroup.Item variant="flush" onClick={() => handleClick(item['place_id'])}>
{item['formatted_address']}
</ListGroup.Item>
))}
</ListGroup>
);
};
Related
I'm currently making a simple web frontend with react using react-autosuggest to search a specified user from a list. I want to try and use the Autosuggest to give suggestion when the user's type in the query in the search field; the suggestion will be based on username of github profiles taken from github user API.
What I want to do is to separate the AutoSuggest.jsx and then import it into Main.jsx then render the Main.jsx in App.js, however it keeps giving me 'TypeError: _ref2 is undefined' and always refer to my onChange function of AutoSuggest.jsx as the problem.
Below is my App.js code:
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import Header from './views/header/Header';
import Main from './views/main/Main';
import Footer from './views/footer/Footer';
const App = () => {
return (
<>
<Header/>
<Main/> <- the autosuggest is imported in here
<Footer/>
</>
);
}
export default App;
Below is my Main.jsx code:
import React, { useState } from 'react';
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
import axios from 'axios';
import { useEffect } from 'react';
import AutoSuggest from '../../components/AutoSuggest';
const Main = () => {
const [userList, setUserList] = useState([]);
useEffect(() => {
axios.get('https://api.github.com/users?per_page=100')
.then((res) => setUserList(res.data))
.catch((err) => console.log(err));
}, [])
return (
<Container>
<br/>
<Row>
<AutoSuggest userList={userList} placeHolderText={'wow'} />
</Row>
</Container>
);
}
export default Main;
Below is my AutoSuggest.jsx code:
import React, { useState } from "react";
import Autosuggest from 'react-autosuggest';
function escapeRegexCharacters(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function getSuggestions(value, userList) {
const escapedValue = escapeRegexCharacters(value.trim());
if (escapedValue === '') {
return [];
}
const regex = new RegExp('^' + escapedValue, 'i');
return userList.filter(user => regex.test(user.login));
}
function getSuggestionValue(suggestion) {
return suggestion.name;
}
function renderSuggestion(suggestion) {
return (
<span>{suggestion.name}</span>
);
}
const AutoSuggest = ({userList, placeHolderText}) => {
const [value, setValue] = useState('');
const [suggestions, setSuggestions] = useState([]);
const onChange = (event, { newValue, method }) => { <- error from console always refer here, I'm not quite sure how to handle it..
setValue(newValue);
};
const onSuggestionsFetchRequested = ({ value }) => {
setValue(getSuggestions(value, userList))
};
const onSuggestionsClearRequested = () => {
setSuggestions([]);
};
const inputProps = {
placeholder: placeHolderText,
value,
onChange: () => onChange()
};
return (
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={() => onSuggestionsFetchRequested()}
onSuggestionsClearRequested={() => onSuggestionsClearRequested()}
getSuggestionValue={() => getSuggestionValue()}
renderSuggestion={() => renderSuggestion()}
inputProps={inputProps} />
);
}
export default AutoSuggest;
The error on browser (Firefox) console:
I have no idea what does the error mean or how it happened and therefore unable to do any workaround.. I also want to ask if what I do here is already considered a good practice or not and maybe some inputs on what I can improve as well to make my code cleaner and web faster. Any input is highly appreciated, thank you in advance!
you have to write it like this... do not use the arrow function in inputProps
onChange: onChange
SOLUTION JAVASCRIPT:
How create to Build a “like button” component using React 16. The component should be the default export (use export default).
Click here image
Personally, I prefer to use functional components instead of using class-based components. One solution to your problem could be the following code.
import React, { useState } from 'react';
const LikeButton = () => {
const [likes, setLikes] = useState(100);
const [isClicked, setIsClicked] = useState(false);
const handleClick = () => {
if (isClicked) {
setLikes(likes - 1);
} else {
setLikes(likes + 1);
}
setIsClicked(!isClicked);
};
return (
<button className={ `like-button ${isClicked && 'liked'}` } onClick={ handleClick }>
<span className="likes-counter">{ `Like | ${likes}` }</span>
</button>
);
};
export default LikeButton;
This question already has answers here:
How do I create a GUID / UUID?
(70 answers)
Closed 12 months ago.
I am mapping an array of data with props into a component. Then onClick I pull some of that data into redux/reducer from the rendered items, trying to render the same data - but in a different spot on the page.
My problem is (I assume?) that the ID's are the same - I render data with keys's/id's that were already taken - while React wants unique ones.
I am not sure, if that's what's causing the problem - but I keep getting a warning that react wants unique key props.
(it's a shop app - on click, i want to add the chosen item to a cart with redux... )
Thoughts?
here I am building the component to render
import { useDispatch, useSelector } from 'react-redux'
import { add } from '../features/addToCart'
export const ReduxshopProps = (props) => {
const dispatch = useDispatch()
const handleAddToCart = (props) => {
dispatch(add(props));
};
return (<>
<div key={props.id} className='shopitem'>
<img src={props.url} />
<h2>{props.title}</h2>
<p className='boldprice'>${props.price}</p>
<button onClick={() => handleAddToCart(props) }
>
ADD TO CART
</button>
</div>
</>
)
}
here I am passing data into the component
import React from "react"
import { ReduxshopProps } from "./ReduxshopProps"
import shopdata from "./shopdata"
export default function ReduxShop() {
const cards = shopdata.map(props => {
return (
<ReduxshopProps
key={props.id}
title={props.title}
price={props.price}
url={props.url}
/>
)
})
return (
<div className='shopwrapper'>
<h1>TradingView Indicators</h1>
<div className='itemWrapper'>
{cards}
</div>
</div>
)
}
here's the REDUX code that pulls data from above
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
cartItems: [],
cartTotalQuantity: 0,
cartTotalAmount: 0,
}
export const addToCartSlice = createSlice({
name: 'cart',
initialState,
reducers: {
add(state, action ) {
const itemIndex = state.cartItems.findIndex(
(item) => item.id === action.payload.id
);
if(itemIndex >= 0){
state.cartItems[itemIndex].cartQuantity += 1
} else {
const tempProduct = {...action.payload, cartQuantity: 1}
state.cartItems.push(tempProduct);
}
},
},
});
export const {add} = addToCartSlice.actions;
export default addToCartSlice.reducer;
and here I'm trying to render the data when someone clicks on a button.. onClick it acts as all components have the same ID - also I'm getting the key prop error from here, below
import React from 'react'
import { useSelector } from 'react-redux'
function Cart() {
const cart = useSelector((state) => state.cart)
return (
<div>
<h1>Cart</h1>
{cart.cartItems.map(cartItem => (
<div key={cartItem.id}>
<p>product : {cartItem.title}</p>
<p>price {cartItem.price}</p>
<p>quantity : {cartItem.cartQuantity}</p>
<p>url : <img src={cartItem.url} /></p>
</div>
))}
</div>
)
}
export default Cart
What you are trying to do is, assign UUID
First in terminal:
npm install uuid
Then:
import { v4 as uuidv4 } from 'uuid';
uuidv4(); // ⇨ '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
More on here, a sof thread: How to create a GUID / UUID
The library, on npm: https://www.npmjs.com/package/uuid
I have created a search box inside component. So I am calling onchange function outside in parent App.js. Now I am trying to dispatch that function if I type anything in search box but I can't access that function outside my class.
How to dispatch my function?
Please find my source code below:
import React, {Component} from "react";
import {connect} from "react-redux";
import { User } from "../components/User";
import { Main } from "../components/Main";
import Data from "../components/Data";
import MovieListing from '../components/MovieListing';
import Header from '../components/Header'
import { setName, getApiData } from "../actions/userActions";
import {apiFetch} from "../actions/dataActions"
import {searchFetch} from "../actions/searchActions"
class App extends Component {
constructor(props){
super(props)
this.searchQuery = this.searchQuery.bind(this);
}
searchQuery( query ) {
}
render() {
let dataSet=this.props.data.data.results;
let imagePath = []
let original_title = []
let release_date = []
let original_language = []
if(dataSet){
dataSet.forEach(function (value, key) {
imagePath.push(<Data key={key} imagePath={value.backdrop_path} release_date={value.release_date} original_title={value.original_title} original_language={value.original_language} />)
original_title.push(value.original_title)
})
return(
<div className="wrapper">
<Header searchQuery = { this.searchQuery } />
<div className="movies-listing">
<div className="container">
<MovieListing imagePath={imagePath} release_date={release_date} original_title={original_title} original_language={original_language} />
</div>
</div>
</div>
)
}else{
return(
<div className="middle-loader">
<h1>Loading</h1>
</div>
)
}
// console.log("this.props",this.props);
}
}
const mapStateToProps = (state) => {
return {
user: state.user,
math: state.math,
data: state.data,
searchData: state.searchData
};
};
const mapDispatchToProps = (dispatch) => {
return dispatch(apiFetch()), {searchQuery: (query) => {searchFetch(query)}}
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
Here I can't access that {searchQuery: (query) => {searchFetch(query)}} because of not accessible that function outside class.
HELP WOULD BE APPRECIATED!!
mapDispatchToProps takes/passes the dispatch function and then return searchQuery function as a prop.
const mapDispatchToProps = (dispatch) => {
return {
searchQuery: (query) => { dispatch(searchFetch(query)) }
}
};
Then in the Header component pass the searchQuery prop
<Header searchQuery={ this.props.searchQuery } />
I've tried to fire an onchange function when my Textfield is filled, but i can't figure out why this function is never fired, even if React devtool plugin for Chrome actually trigger the changes, any advice ?
import React, {Component} from 'react';
import {Tracker} from 'meteor/tracker';
import {Meteor} from 'meteor/meteor';
import {Links} from '../api/links';
import LinkListItem from './LinkListItem';
import {Session} from 'meteor/session';
import SearchLink from './SearchLink';
import Fuse from 'fuse.js';
export default class LinkList extends Component {
constructor(props) {
super(props);
this.state = {
links: [],
inputValue: ''
};
}
componentDidMount() {
this.linksTracker = Tracker.autorun(() => {
Meteor.subscribe('links');
const links = Links.find({visible:
Session.get('showVisible')}).fetch();
this.setState({links});
});
}
componentWillUnmount() {
this.linksTracker.stop();
}
renderLinksListItems() {
if (this.state.links.length === 0) {
return (
<div>
<h2 className="link">{Session.get('showVisible') ? 'No links found' : 'No hidden links found'}</h2>
</div>
);
}
console.log(this.state.links);
return this.state.links.map((link) => {
const shortUrl = Meteor.absoluteUrl(link._id);
return <LinkListItem key={link._id} shortUrl={shortUrl} {...link}/>;
});
}
_onChange(e) {
if(e.target.value === "") {
return;
}
var fuse = new Fuse(this.state.links, { keys: ["url"]});
var result = fuse.search(e.target.value);
this.setState({
inputValue: e.target.value,
links: result
});
}
render() {
return (
<div>
<div>
<SearchLink onChange={this._onChange} value={this.state.inputValue}/>
</div>
<div>{this.renderLinksListItems()}</div>
</div>
);
}
}
My Textfield component :
import React from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import TextField from 'material-ui/TextField';
const muiTheme = getMuiTheme({
palette: {
primary1Color: '#ef6c00'
}
})
const SearchLink = () => (
<MuiThemeProvider muiTheme={muiTheme}>
<TextField floatingLabelText="Search a Link" name="searchLink" fullWidth={true}/>
</MuiThemeProvider>
);
export default SearchLink;
Thank you for your help!
Do these changes:
1. Bind the method in Parent component LinkList, because you are using this.setState inside onChange method, if you don't bind it, it will throw the error, bind it like this:
<SearchLink onChange={this._onChange.bind(this)} value={this.state.inputValue}/>
or define the binding in constructor.
2. You are passing the event and value in props, so you need to define those values in TextField, like this:
const SearchLink = (props) => (
<MuiThemeProvider muiTheme={muiTheme}>
<TextField
onChange = {props.onChange}
value = {props.value}
floatingLabelText = "Search a Link"
name = "searchLink"
fullWidth = {true}/>
</MuiThemeProvider>
);