Passing parameters to a props function in React - javascript

I wrote two sample components to show what I'm trying to do.
If the call was from the same class, I could do like below.
onClick={this.myFunc.bind(this, param1, param2)}
How do I do the same thing from a stateless component without the need to mess with binding 'this'.
onClick={props.onClick['need to add params']}
import React from 'react';
class BigComponent extends React.Component{
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(param1, param2){
// do something with parameters
}
render(){
return(
<div>
<SmallComponent handleClick={this.handleClick}/>
</div>
);
}
}
function SmallComponent(props){
return(
<div>
<button onClick={ () => {props.handleClick('value_1', 'value_2')}}></button>
<button onClick={ () => {props.handleClick('value_3', 'value_4')}}></button>
{/* how to do above without arrow functions, because I read that it's not optimized*/}
</div>
);
}

Add a callback inside of this.myFunc.
this.myFunc = event => (param1, param2) => { ... do stuff }
In your top level component you can do:
handleClick={this.myFunc}
In your child, just do:
onClick={handleClick(param1, param2)}
Hope this is helps.
Alternatively you can do the following:
function SmallComponent(props){
const handleClick = (param1, param2) => (event) => props.handleClick(param1, param2);
return(
<div>
<button onClick={handleClick(param1, param2)}></button>
...
);
}

Related

Pass arguments to function in React (API)

Today I started learning React, and I want to fetch movies from the TMDb API. I have this code:
getMovies() {
const APIKey = "MYAPI";
fetch(`https://api.themoviedb.org/3/search/company?api_key=${APIKey}&query=${argument}&page=1`)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
}
And in my render() I have this:
return (
<Fragment>
<div className="Main">
<button onClick={this.getMovies.bind('spider-man')}>Get</button>
</div>
</Fragment>
)
I want to pass 'spider-man' as an argument to do the search in the TMDb API. Hope you can help me!
This is how you can pass the parameter to the class component function, using {() => {...}} or other option could be this.getMovies.bind(this, 'spider-man')
getMovies(movie) { // your code here}
Option 1:
return (
<Fragment>
<div className="Main">
<button onClick={() => this.getMovies('spider-man')}>Get</button>
</div>
</Fragment>
)
Option 2:
return (
<Fragment>
<div className="Main">
<button onClick={() => this.getMovies.bind(this,'spider-man')}>Get</button>
</div>
</Fragment>
)
This is mainly divided into two categories
Class components
Functional Components
Class components
Consider you have your code as follow:
getMovies(movieName){...}
render(){
<button onClick={/*Attach event here*/}>Get</button>
}
There can be 4 ways
Using binding in the constructor, This is a recommended way of binding a method.
class Movie{
constructor(props){
super(props);
this.getMovies = this.getMovies.bind(this);
}
getMovies(movieName){ //your code }
render(){
<button onClick={this.getMovies('some_movie_name')}>Get</button>
}
}
Using binding in the render method itself. In terms of performance, it's the same as the previous one. The first one is a little cleaner for me.
class Movie{
getMovies(movieName){ //your code }
render(){
<button onClick={this.getMovies.bind('some_movie_name')}>Get</button>
}
}
Using arrow function syntax in render().
class Movie{
getMovies(movieName){ //your code }
render(){
<button onClick={()=>this.getMovies('some_movie_name')}>Get</button>
}
}
Using the arrow function in classes. This will have an impact on overall performance. You can read more about this here.
class Movie{
getMovies = (movieName) => { //your code }
render(){
<button onClick={this.getMovies('some_movie_name')}>Get</button>
}
}
Function components
Consider you have your code as follow:
function getMovies(movieName){ //your code }
return(){
<button onClick={/*Attach event here*/}>Get</button>
}
There aren't many variations for the function component. Using either an arrow or regular function expression to define a function.
function Movie(){
function getMovies(movieName){...} //or const getMovies = (movieName) => {...}
return(
<button onClick={()=>getMovies('some_movie_name')}>Get</button>
{/*
if not arguments
<button onClick={getMovies}>Get</button>
*/}
)
}

React JS: Calling two functions in an onClick event does not run functions

I'm using React and React Spring. React spring has a toggle function that essentially maximizes a window on click. It looks like this:
class Projects extends Component {
constructor() {
super()
this.state = {
instructions: true,
data: ''
}
}
handleClick () {
console.log('hello world');
this.setState({
instructions: false
});
console.log(this.state.instructions);
return true;
}
render() {
return (
{this.state.instructions && (
<div className="projects-instructions">
Instructions here
</div>
)}
<Grid
className="projects"
data={data}
keys={d => d.name}
heights={d => d.height}
columns={2}>
{(data, maximized, toggle) => (
<div onClick={()=>{
return data.clicks ? toggle() : false
}}>
</div>
)}
</Grid>
);
}
}
export default Projects;
What I want to do, is hide the instructions on click. I can make this happen by calling handleClick via, this.handleClick.bind(this) in my onClick tag via: onClick={this.handleClick.bind(this)}. But that means I have to remove the toggle onClick function. So I found that I could call two functions like so:
onClick={()=>{
this.handleClick.bind(this);
return data.clicks ? toggle() : false;
}}
The issue is that this.handleClick.bind(this) never runs. console.log doesn't even run.
How should I be doing this?
Binding this to a function does not call the function. It simply specifies what this refers to when used within that function. Bind to this in the constructor, and then, in your onClick event, simply call the function normally (i.e. this.handleClick()).
class Projects extends Component {
constructor() {
super();
this.state = {
instructions: true,
data: ''
}
//this is where you bind `this` to methods
this.handleClick = this.handleClick.bind(this);
}
handleClick () {
console.log('hello world');
this.setState({
instructions: false
});
console.log(this.state.instructions);
return true;
}
render() {
return (
{this.state.instructions && (
<div className="projects-instructions">
Instructions here
</div>
)}
<Grid
className="projects"
data={data}
keys={d => d.name}
heights={d => d.height}
columns={2}>
{(data, maximized, toggle) => (
<div onClick={()=>{
this.handleClick();
return data.clicks ? toggle() : false
}}>
</div>
)}
</Grid>
);
}
}
export default Projects;

ReactJS remove dynamic element

i want to remove dynamic element in my program, but i think, i have problem with 'this'.When i click in 'X', nothing happens, console doesn't show any error. Maybe someone more experienced will help me.
('items' is array in state)
Main file:
removeItemCity(i){
let arr = this.state.items;
arr.splice(i, 1);
this.setState({items:arr})
}
renderItems(item,i){
return(<Tiles key = {'key_' + i} index = {i} delete = {() =>
{this.removeItemCity}}/>);
}
render() {
return(
<div className = "BodyAppContainer">
<div className = "grid" id="items">
{this.state.items.map(this.renderItems) }
</div>
</div>
);
}
And my component "Tiles"
import React from 'react';
class Tiles extends React.Component {
constructor(props) {
super(props);
}
remove(){
this.props.delete(this.props.index);
}
render() {
return (
<div className = "col-4_sm-6_xs-12 item">
<h2>City : {this.props.index}</h2>
<button className="removeButton" onClick={() => this.remove} >X</button>
</div>
);
}
}
export default Tiles;
Your onClick prop for the X button is not doing anything:
onClick={() => this.remove}
When you click, it calls that arrow function. But that arrow function only has this.remove, which is the definition to a method. The first step in helping you out is you should call that method using parentheses:
onClick={() => this.remove()}
The same thing applies to your renderItems(), where you are also missing parentheses to enact a function call in the delete prop passed to Tiles:
delete={() => {this.removeItemCity}}
Try this:
<button className="removeButton" onClick={this.remove} >X</button>

How to get a React component in a function by onClick

I need to get a component that I cliked and see its target property. I try to get it but the evt param is undefined
getcomponent(evt){
console.log(evt.target)
//...
}
//...
render() {
return (<button id="btn" onClick={() =>this.getcomponent()}></button>);
}
You didn't pass the event to function call. Pass the event like this:
onClick={(evt) => this.getcomponent(evt)}.
Add event as a parameter to the onClick:
render() {
return (<button id="btn" onClick={(event) =>this.getcomponent(event)}></button>);
}
Make code short and simple:
onClick = event => {
console.log(event.target)
}
render() {
return <button id="btn" onClick={this.onClick}></button>
}
You need to pass event in order to get it back. Here is the code.
class TestJS extends React.Component {
constructor(props) {
super(props);
this.getcomponent = this.getcomponent.bind(this);
}
getcomponent(event){
console.log(event.target);
}
render() {
return(
<div id="root">
<button id="btn" onClick={(event) =>this.getcomponent(event)}></button>;
</div>
)};
}
export default TestJS;

ReactJS: e.preventDefault() is not a function

I'm making a simple todo app, where i have put in the logic to edit and delete the todos as well. I'm trying to update the parent state from child component but when i'm trying to click on delete it is throwing me an error e.preventDefault() is not a function and it is removing all of the todos here are the components:
PARENT
export default class App extends React.Component {
constructor(props){
super(props);
this.state = {
listArr: [],
}
}
deleteTodos(i) {
var lists = this.state.listArr;
lists.splice(i, 1);
this.setState({listArr: lists})
}
render() {
.......
<ToDoList {...this.state} passDeleteTodos={this.deleteTodos} />
......
}
CHILD
export class ToDoList extends React.Component {
constructor(props) {
super(props);
this.state = {
editing: false,
};
handleDelete(e, i) {
e.preventDefault();
this.props.passDeleteTodos()
}
renderDisplay() {
return(
<div>
{
this.props.listArr.map((list,i) => {
return(
<div key={i} index={i} ref="text">
<li>{list}
<div style={{float: 'right'}}>
<button className="btn btn-danger btn-xs glyphicon glyphicon-trash"
onClick={() => this.handleDelete(i)}
/>
</div>
</div>
</div>
You need to pass the event object to handleDelete function when you make use of Arrow function as done in your implementation.
You can think of an arrow function like a function that calls another function to which you need to pass the arguments. Event object is a parameter to the arrow function and you indeed need to pass this on to the handleDelete function
onClick={(e) => this.handleDelete(e, i)}
However after this change you still need to bind the deleteTodos function in the parent, since the context of this inside this function won't be that of the React class component, you can do it like
deleteTodos = (i) => {
var lists = this.state.listArr;
lists.splice(i, 1);
this.setState({listArr: lists})
}
or
constructor(props){
super(props);
this.state = {
listArr: [],
}
this.deleteTodos = this.deleteTodos.bind(this);
}
I change e.preventDefault() => e.preventDefault and bind the function.
Example
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
listArr: [],
}
this.deleteTodos = this.deleteTodos.bind(this)
}
handleDelete(e, i) {
e.preventDefault;
this.props.passDeleteTodos()
...
}
render() {
return(
<div>
{
this.props.listArr.map((list,i) => {
return(
<div key={i} index={i} ref="text">
<li>{list}
<div style={{float: 'right'}}>
<button className="btn btn-danger btn-xs glyphicon glyphicon-trash"
onClick={(e,i) => this.handleDelete(e,i)}
/>
</div>
</div>
)}
}
</div>
You are not sending e to the correspondent method.
You could also bind the event
onClick={this.handleDelete.bind(this, i)}
Same applies for deleteTodos in the App component.
Either way you can use the same approach or bind it in the constructor:
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
listArr: [],
}
this.deleteTodos = this.deleteTodos.bind(this)
}
...
}
doesn't behave the same way as an so you can't expect the same preventDefault call.
But your problem is you in bind the order of params change. So you're binded param becomes first in the function. See my snippet below.
const App = () => {
const _click = (externalVar, e) => {
console.log("PARAMS", externalVar, e);
};
const externalVar = 1
return (
<button onClick={_click.bind(undefined, externalVar)}>click me</button>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Like it says here
fun.bind(thisArg[, arg1[, arg2[, ...]]])
arg1, arg2, ... Arguments to prepend to arguments provided to the
bound function when invoking the target function.
arrow function in react doesn't need to bind to this.
But during call to the functions, for example to call this function handleDelete
handleDelete(e, i) {
e.preventDefault();
this.props.passDeleteTodos()
}
we will use synatx as:
handleDelete.bind(i)
handleDelete(e, i) {
e.preventDefault();
this.props.passDeleteTodos()
...
}
onClick={(e,i) => this.handleDelete(e,i)}
if the above code is not working properly try this.
handleDelete(i) {
this.props.passDeleteTodos()
...
}
onClick={(e,i) => {e.preventDefault(); this.handleDelete(i)}}

Categories