this."FunctionName" is not a function - javascript

I would like using a function in the render() who will be calling multiple time because it's call for each element of a Map(). But for some reasons my function is not recognized correctly, I get the error :
this.IsHeStillAlive is not a function
I totally rewrote my post to make it easier to understand and here is the link for my exemple on SandBox : https://codesandbox.io/s/test-uz-713xy.
in this exemple I try to use the functions "IsHeStillAlive" and "SwitchButton".
thanks for your help.

You can try with Ternary operator as the following:
<div className="slave">
<h3>{panel.price}€</h3><br/>
{
panel.name === 'Basique' ?
<Button className="buttonStore"
onClick={() => { this.UnsubcribeIt() }}>
Unsubscribe
</Button> :
<Button className="buttonStore"
onClick={() => { this.buyit(licenceName) }}>
Buy Now
</Button>
}
</div>
Or shorter in the first <Button /> as onClick={this.UnsubcribeIt}.

I think you should extract dataGet first so it wont have confusing this
render(){
let {dataGet} = this.state
return (
{this.state.dataGet.map(mapPanel)}
)
}
tell me if that is working

Someone outside this forum find me a solution.
The correction is in my sandbox link but if one day the lin is dead ...
just in case here are the step to correct my issue:
move your methods out of the class,make them a function components in the same file.
change the panel param to props . Inside props will be a panel prop
render the components like
it will not be very explicit if the sandbox link is dead but that will maybe help.

Related

How can i display different component in map()

I have a Card component and a QuestionCard component.
what I want to do is when a user uploads a post or asks a question, it shows the respective component. And this is my idea of doing it :
const CardList = ({cardList}) => {
return (
<div className="cardWrapper">
<div className="cardColumn">
{cardList.map((card)=>{
if(){
<Card />
} else{
<QuestionCard />
}
})}
</div>
but I don't know what to fill in the expression. Am I have the right idea? Or there are some other ways to do it?
Here is some reference how what it should look like:
reference
Make sure you return the component to be rendered inside map.
if (){
return <Card / > ;
}
else {
return <QuestionCard / > ;
}
If I understand correctly:
If a question is asked by the user — we wish to render <QuestionCard />;
If a post is uploaded by the user — we wish to render <Card />.
First off, you need a way to determine if the looped-over object is a question or a post:
One way of doing so is adding 1 or 2 boolean properties to your cardList array of objects:
isQuestion — if set to true then the card is a question;
isPost — if set to true then the card is an uploaded post.
In fact, one of the two is plenty enough for this use case.
card.isQuestion ? (Render <QuestionCard/>) : (Render <Card />)
I am using a ternary operator because it is easier to read than an if statement.
Provided that's what you want to do, your test would look like this:
{cardList.map((card, id) =>
card.isPost ? ( // Render <Card /> if the card is a post
<Card key={id} />
) : ( // If the card isn't an uploaded post then it is necessarily a question
<QuestionCard key={id} />
)
)}
P.S. You should probably use NextJS' dynamic styling system depending on how much your project is going to scale, to avoid any mix-ups between the same classname in different files in the future.

Fix a 'Cannot read property handleClick of undefined error' (and issues related to deleting an item from the DOM)

Background
I'm working on a final project for school that displays a list of tv shows/programs using cards. I am trying to set up a way to delete a card. I'm getting all sorts of turned around trying to get this delete to work on my frontend. I've spent so long researching the issue that every solution I think of now seems both right and wrong.
First, there was a problem where programId was undefined which I fixed. Now I can't figure out how make make my this in this.handleClick work. This solution made me think that I might need to use bind. But I am not sure.
Code
This is a section of my Program.js file, where the card is styled and props passed in to populate fields like name, network, and image. I use props.match.params because I've implemented React Router and need to access each card's data for the ternary statements inside. EDIT: Program.js is a functional component. I've included a link.
let handleClick = (id) => {
this.props.deleteProgram(id)
}
let program = props.program ? props.program : props.programs[props.match.params.id - 1]
let programId = program.id
return(
<Grid.Column>
<Card onClick={(_) => this.handleClick(programId)}>
<Image src={program ? program.image : null} wrapped ui={false} />
<Card.Content>
<Card.Header>{program ? program.name: null}</Card.Header>
<Card.Meta>
<span className='date'>{program ? program.network : null
</span>
</Card.Meta>
Here is my Programs.js file, which creates each Program component. I am unsure whether I should import my {deleteProgram} action/function in this file where I am creating each Program, or if I need to import it directly in Program.
EDIT: Programs.js is a functional component. I've added a link.
<Grid columns='six' divided='vertically'>
<Grid.Row >
{props.programs.map((program) => <Program key={program.id} program={program} />)}
</Grid.Row>
</Grid>
This is the programsReducer file with the case statement for deleting a program.
case 'DELETE_PROGRAM':
const programs = state.programs.filter(program => program.id !==
action.id)
return {programs}
Here is my deleteProgram action/function.
return (dispatch) => {
fetch(`http://localhost:3000/api/v1/programs/${id}`,{
method: 'DELETE',
headers: {'Content-Type': 'application/json'}
})
.then(res => res.json())
.then(res => dispatch({type: 'DELETE_PROGRAM', id: id}))
}
}
Recap of Questions
Do you know why I am getting an error that this in my this.handleSubmit is undefined?
Which file --Programs.js (with the .map) or Program.js (which each individual card -- should I import my {deleteProgram} function/action into?
Bonus Round
If memory serves, I need to put this onClick method on the entire card. I would love to call it on a delete button I made within the card. Can someone confirm whether this is correct or not?
Thank you very much for your time! :-)
Change your code to the following:
let handleClick = (id) => {
props.deleteProgram(id)
}
let program = props.program ? props.program : props.programs[props.match.params.id - 1]
let programId = program.id
return(
<Grid.Column>
<Card onClick={(_) => handleClick(programId)}>
<Image src={program ? program.image : null} wrapped ui={false} />
<Card.Content>
<Card.Header>{program ? program.name: null}</Card.Header>
<Card.Meta>
<span className='date'>{program ? program.network : null
</span>
</Card.Meta>
Question 1: One of the ways to bind this is in the constructor of the component.
this.function = this.function.bind(this);
Regarding Question 2: I would send the deleteCardFunction() in as a prop for each individual card. Then call it from the card with the id when you want to delete it.
Since this is a function component, not a class, you shouldn't use this there. Just use the function name.
<Card onClick={() => handleClick(programId)}>
should even work without binding it in there, since you are already doing it with an arrow function in the function declaration:
<Card onClick={handleClick(programId)}>
I would import delete into Program.js, since it makes sense to have the delete button inside that.
Another neat trick, instead of using the ? : shorthand, you can do it even shorter, using ||, like:
let program = props.program || props.programs[props.match.params.id - 1]
To be able to put another onClick inside the card, you will have to stop the event from bubbling up, calling event.stopPropagation() before or inside your delete method.

React conditional onClick with ampersand

I want to edit a card if allowed=true. I came up with this solution:
const editCard = (onEdit, id, allowed) => {
if (allowed) {
onEdit(id);
}
};
<Card onClick={() => editCard(onEdit, id, allowed)}>Card</Card>
I thought of making a simpler onClick like so:
<Card onClick={() => allowed && onEdit(id)}>Card</Card>
Can I make on onClick like so with the ampersand? If allowed=true then edit, otherwise onClick should not do anything.
It seems to work but I don't know if it will always work. Can this cause bugs and is there a better way to implement this click event?
Yes, it will work as expected :)
true && something() calls something function
false && something() returns just false while not calling something
Yes, that will work. But you may also use like:
<Card allowed onClick={() => onEdit(id)}>Card</Card>
Then check the allowed props.
Just using allowed is equivalent to allowed={true}. If the allowed option is false you want to send, you don't need to pass the props.
But in your case, it's dynamic. So, you can use like:
<Card allowed={allowed} onClick={() => onEdit(id)}>Card</Card>
So, depending on the case it will be either allowed={true} or allowed={false}.
And oh, you want to use it in editCard, so you may just use like:
<Card onClick={() => onEdit(id, allowed)}>Card</Card>
A good use case with conditional statement would be to use like: (only show card if allowed is true)
{
allowed &&
<Card onClick={() => onEdit(id)}>Card</Card>
}
This way, you're ensuring clear instruction with your code. So, you found sorts of ways. Happy coding!

React getting the ID of clicked button

I have 5 clickable links, each with unique ID. I am trying to get the ID of the link that was clicked. I have tried two methods but neither work as I would like.
Inside render I have:
this.state.data.map((dynamicData, key) =>
<a href={"/#/template"} id={dynamicData.id} onClick={() => this.reply_click(this.id)}>{dynamicData.name}</a>
Edit</button>
Basic method that returns undefined. What am I doing wrong?:
reply_click(clicked_id) {
console.log(clicked_id);
}
Using an arrow function will maintain the context of this from the outside, which won't be the this you want. You could try to use a regular function (function () { }) instead, but I'm not sure if this will be what you want or not there either.
You can, however, definitely use e.target.id to get what you want:
onClick={e => this.reply_click(e.target.id)}
That said, you should really avoid creating functions inside of things as it can create significant performance issues. It's much better to just create a function and pass it in:
// somewhere above
const handleClick = e => this.reply_click(e.target.id);
// attribute
onClick={handleClick}
you can do this
<a href={"/#/template"} id={dynamicData.id} onClick={() => this.reply_click(dynamicData.id)}>{dynamicData.name}</a>
or another way
<a href={"/#/template"} id={dynamicData.id} onClick={this.reply_click}>{dynamicData.name}</a>
reply_click(event) {
console.log(event.target.getAttribute('id'))
}
this.reply_click(this.id)
this is your component scope, which means every attribute you defined in your component can be accessed by this. Probably you did not define id in this component.
You probably wanna do
this.reply_click(dynamicData.id)
instead.
The this inside the arrow function is the same as the this outside it. The onclick is already aware of the correct this, so use it like this:
onClick={this.reply_click(this.id)}
Try this code. The code you have provided doesn't work because this is bound to the current React component, instead you could access id of the clicked element using e.target.id:
this.state.data.map((dynamicData, key) => {
<a href="/#/template" id={dynamicData.id} onClick={(e) => this.reply_click(e.target.id)}>{dynamicData.name}</a>
<button type="button" class="btn-lisa">Edit</button>
})
Unrelated, but still I want to note that you don't have to use <a href={"blah"} instead you can use <a href="blah" because the last one uses a string contant.

Can you add a key to a React JSX Element after it's instantiated?

Given the following:
function generateWrapper(...elements) {
return (
<div>
{...elements}
</div>
);
}
ReactDOM.render(
generateWrapper(
<MyElement name="first" />,
<MyElement name="second" />,
),
document.getElementById("app"),
);
React will rightfully complain that I haven't added a key property to each of the children of the wrapper div. How can I do this? Or is this against the spirit of react development? Thanks for any answers in advance!
PS: Yes there is a similar question I looked at but it seemed to be targeting users not using JSX
PPS: I do realize I can merely add a key to first and second MyElement's but this is what I'm attempting to avoid
edit: Changing code to better suit my circumstances
Take a look at React.cloneElement. You could use that to create and attach the key property inside your generateWrapper method.
function generateWrapper(...elements) {
return (
<div>
{
elements.map(element =>
React.cloneElement(element, { key: 'your-unique-key-here' })
}
</div>
);
}

Categories

Resources