Passing down variable to handler in sub component in ReactJS - javascript

I have a AllPersons component, where I want to pass down a callback from my main app.js component, I want it so, I can edit a person, that I'm displaying inside my table.
My issue is that I need the id of the person, in order to change just that one person.
I'm mapping through an array of person objects and adding a button to make the callback
However, I need to pass the id inside to the handler so I can edit just that person
<div className="col-md-6">
<h3>All Persons</h3>
<AllPersons persons={this.state.persons} onEdit=
{this.onEditHandler} id={this.id} />
</div>
//AllPersons.js
{persons.map((person, i) => (
<tr key={i}>
<th>{person.age}</th>
<th>{person.name}</th>
<th>{person.gender}</th>
<th>{person.email}</th>
<a href="/#" onClick= {props.onEdit} id={person.id}>edit</a>
</tr>
//handle method inside App.js
onEditHandler = (event) =>{
event.preventDefault();
console.log("editet")
}
I was considering setting the id as a state, but I think that would be too much,

Use curryng for this case
Define you hander like this
editHandler = id => event => {
// you have id here
}
And use it in JSX
<a href="/#" onClick= {props.onEdit(person.id)}>edit</a>

Related

Passing function and params through react props

I have an dropdown menu with buttons for the dropdown elements and pressing them causes an fucntion call.
`
<div className = "dropdown-container">
<button className = "dropdown-button"> Sort </button>
<div className = "dropdown-content">
<button className = "sort-button" onClick={() => changeFilter(['sort=-Covered_distance'])}> Furthest </button>
<button className = "sort-button" onClick={() => changeFilter(['sort=+Covered_distance'])}> Shortest </button>
<button className = "sort-button" onClick={() => changeFilter(['sort=-Duration'])}> Longest </button>
<button className = "sort-button" onClick={() => changeFilter(['sort=+Duration'])}> Fastest </button>
</div>
</div>
Im trying to clean up my code as I have multiple dropdown menus next to each other with the same principle. I thought about making a react component that has the structure of the dropdown menu but as I have an function call in it I need to pass this through also so like.
<div className = "filters-container">
<Dropdown changeFilter = { () => changeFilter() }/>
</div>
Now this works as it calls the function changeFilter(), but none of the params from the other component gets called with the call so it basically calls only changeFilter(), when I press any of the buttons. How can I get the params with the call?
You must pass the argument in the changeFilter prop.
For example:
<div className="filters-container">
<Dropdown changeFilter={() => changeFilter(['sort=-Covered_distance'])} />
</div>
Here's a working example:
https://codesandbox.io/s/falling-currying-kd0oco?file=/src/App.js
The problem here is that when you pass a function as a prop, you can't change their parameters inside the component, the parameter has to be passed from the parent.
Pass the paramter ['sort=-Covered_distance'] in changeFilter function like this:
<div className = "filters-container">
<Dropdown changeFilter={() => changeFilter(['sort=-Covered_distance'])} />
</div

ReactJS: Determining the index of an item in an array, that is passed from another file. (Using Ant Design)

I have a file with some Javascript code that consists of an array, with multiple object within (with key:value pairs).
Initially, in my main file (App.jsx) I create a State Variable and set it to the array in my other JS file. I am now trying to add a button, which when I click I can determine which Object (item) within the array the value belongs to.
<List
bordered
className="list-default"
dataSource={requestInfo}
renderItem={(item) => (
<Space>
<List.Item>
<h4>{"Request Id: " + item.requestId}</h4>
<div>
{"Request DateTime: " + item.requestDateTime}
</div>
</List.Item>
<Button type="text" onClick={showDetails}>
>>
</Button>
Here's a snippet of my code. Basically, the 'item' in the inline function is one of the objects from the array (requestInfo -> which is a statevariable). I want it to be such that, the button can store the index of the object (item) as its ID. Thanks for your help!
In your Button declaration, you are passing a function reference to onClick prop:
<Button type="text" onClick={showDetails}>
which is a shortcut to:
<Button type="text" onClick={(clickEvent) => showDetails(clickEvent)}>
So you can expand this, and call the function with parameters that you need:
<Button type="text" onClick={() => showDetails(item.requestId)}>

Why props alone are being used in called React function component?

I was learning React and I came to a point which created confusion. Everywhere I was using props while writing Function components.
I always use props.profile and it works fine. But in one code component, I had to write
const profiles=props; and it worked fine.
I tried using const profiles=props.profile; and also I tried using inside return in 'Card' function component
{props.profile.avatar_url} but both of them failed
Below is my code which works fine
const Card=(props)=>{
const profiles=props; //This I dont understand
return(
<div>
<div>
<img src={profiles.avatar_url} width="75px" alt="profile pic"/>
</div>
<div>
<div>{profiles.name}</div>
<div>{profiles.company}</div>
</div>
</div>
);
}
const CardList=(props)=>{
return(
<div>
{testDataArr.map(profile=><Card {...profile}/>)}
</div>
);
}
Can someone please help me understand why I can't use const profiles=props.profile?
What are the other ways to achieve the correct result?
Your testDataArr might be this,
testDataArr = [{avatar_url:"",name:"",company:""},{avatar_url:"",name:"",company:""},{avatar_url:"",name:"",company:""}]
Now when you do this,
{testDataArr.map(profile=><Card {...profile}/>)}
here profile = {avatar_url:"",name:"",company:""},
and when you do,
<Card {...profile}/>
is equivalent to,
<Card avatar_url="" name="" company=""/>
In child component, when you do this,
const profiles=props;
here props = {avatar_url:"",name:"",company:""}
So you can access it's values,
props.avatar_url
props.name
props.company
But when you do this,
const profiles=props.profile
profile key is not present in {avatar_url:"",name:"",company:""} object and it fails.
OK. Here is the issue, the props object does not contain a profile attribute, but IT IS the profile attribute. Becouse you are spreading the profile variable when you render the Card element (in the CardList), you basically are writing:
<Card avatarUrl={profile.avatarUrl} comapny={profile.comany} />
Instead, you should do
<Card profile={profile} />
and then in your Card component access the data this way
const Card = (props) => {
const profile = props.profile
}
or even simpler
const Card = ({profile}) => {
return <div>{profile.comany}</div>
}

Pass a multiple arguments from a child props to the parent method

I am new to react js . Here, what I am trying to do is that , I have a parent component which is like:
onchange(event) {
console.log("function will be callled", event.target.value, event.target.id);
{ (this.props.lowData) && this.props.lowData.Low.length > 0 && this.props.lowData.Low.map(data => (
<LowRow technologies={this.state.technologies} onChange={this.onchange.bind(this)} data={data} key={data.id} />
))}
Here there is a onchnage method I am passing as a props to the child element, which is:
<select className="selectpicker btn btn-labeled btn-start selectId techDrop margin-left-10" onChange={props.onChange}>
<option disabled selected value>None Selected</option>
{props.technologies && <Select techData={props.technologies} options={props.technologyName} />}
</select>
So, Now what I want to do is that, In the child when user changes:
onChange={props.onChange}
this gets called in parent element, so here I also want to pass one more parameter with this like:
onChange = {props.onChange, props.id}so that Parent will get one Id as well, But its not working . And also I tried with the `props.onChange(props.id)` But no luck. Can any one help me with this ?
Parent onchange function will receive id in 2nd argument.
onchange(event, id) {
console.log("function will be callled", event.target.value, id);
}
While calling from child you call like this.
onChange={(e)=> {props.onChange(e, props.id)}}
First thing you are not recommended to bind a function directly in render. Because when you bind a function directly in render your component will render for many reasons like setState, when new props received etc. so every time it renders it will create a new function in webpack generated bundle file so the file size becomes large. so always do binding in constructor
Now regarding your issue. Do map in render directly and pass onChange as a prop down to LowRow component. You need to do something like below to pass a function as a prop and send params to it in child component and access it in parent component. This concept is called callbacks in react.
One more thing never forget to add a key to parent jsx element whenever you generate jsx elements in loop. The key should be a unique id from data. If your data don't conatin unique id then pass index as key like key={"key" +index}
constructor(props){
super(props);
this.onChange = this.onChange.bind(this);
}
onChange(event, id) {
console.log("test", event, id);
}
render(){
const { lowData } = this.props;
return(
<div>
{this.props.lowData && this.props.lowData.Low.map(data => (
<LowRow key={data.id} technologies={this.state.technologies} onChange={this.onChange} data={data} key={data.id} />
))}
</div>
)
}
Select onChange
Here not sure what id are you passing. but you can pass params like how I did in the below code
<select className="selectpicker btn btn-labeled btn-start selectId techDrop margin-left-10" onChange={e => props.onChange(e, id)}>
<option disabled selected value>None Selected</option>
{props.technologies && <Select techData={props.technologies} options={props.technologyName} />}
</select>

creating elements in React

I don't understand how elements are created in React.
I have some code below where the goal is to create elements on a form submit using a value from a refs - so for every submit in a form, it creates a new <h1> tag with the content of the textbox inside of it. A sample of what I'm trying to do looks like:
...
addHeader(e) {
e.preventDefault();
const newHeader = this.refs.post.value;
var newpost = React.createElement("h1", {
type: "text",
value: newHeader
});
}
...
render() {
return (
<div className="form-section">
{ newPost }
<form onSubmit={this.addHeader.bind(this)}>
<input id="input-post" type="text" placeholder="Post Here" ref="post" />
<input type="submit" value="Submit" />
</form>
<button className="form-section__submit" onClick={this.clearFields.bind(this)}>Clear All</button>
</div>
);
}
Basically my thinking is in my addHeader() function I'm assigning a variable of newPost to the method and calling it within my component. This code is causing 2 errors:
33:9 warning 'newpost' is assigned a value but never used no-unused-vars
49:13 error 'newPost' is not defined no-undef
What I don't understand, is (from what I can see) I am assigning a value to that variable and also using it in the component that I am rendering... along with that, I don't understand this error message. How can something be assigned a value but be undefined at the same time...? Is it because it's in the wrong scope? How do I declare where the new element is rendered specifically in the component?
I read the documentation but it doesn't give a clear answer as to how to control where in the component the new element is rendered.
Made some changes to your code. You're going to want to initialize component state in your constructor. In your addHeader method you will use this.setState to update the state of the component with a new posts value including the value of this.input. I changed your ref on the input an actual ref. You take the element and store on this. Every time you add a new post you will get a new <h1> with the value of the textarea.
...
addHeader(e) {
e.preventDefault();
this.setState((prevState, props) => {
return { posts: [ ...prevState.posts, this.input.value ] };
});
}
...
render() {
const { posts } = this.state;
return (
<div className="form-section">
{ posts.map( text => <h1>{ text }</h1> ) }
<form onSubmit={this.addHeader.bind(this)}>
<input id="input-post" type="text" placeholder="Post Here" ref={ el => this.input = ref } />
<input type="submit" value="Submit" />
</form>
<button className="form-section__submit" onClick={this.clearFields.bind(this)}>Clear All</button>
</div>
);
}
As an aside: Binding functions in the render method of react components will cause a performance hit. There is no need to re-bind the this context of the function on every render. this.clearFields.bind(this) should become this.clearFields and you will need to add this.clearFields = this.clearFields.bind(this) to your constructor. You do not need to bind functions that are not used as callbacks.
You're going to want to do the same thing for this.addHeader.bind(this).

Categories

Resources