I want to edit user details so I have
<button onClick={() => this.edit(n.id)}>Edit</button>
edit = (id) => {
<Editbranches/>
}
Here Editbranches is another component.How Can i call Component inside a user function?please Help
If you meant to render the Editbranches then:
<button onClick={() => this.setState({ edit: n.id })}>Edit</button>
{
this.state.edit && <Editbranches/>
}
Related
const onSubmit = (event, val) => {
console.log(val);
event.preventDefault();
setValues({ ...values, error: "", success: "", key: val });
setDidSubmit(true);
};
Using map in React:
{data.map((e) => ( <li key={e._id}> <button
onClick={(e) => onSubmit(e, e._id)}
className="btnx btn-primary"
>
Book Now logout
</button> </li> )}
onClick I want to pass unique id e._id to the onSubmit function.
But I'm getting output as undefined.
Edit :- can you also please provide the output of e argument that you passed into the map callback ?
onClick takes a callback function and pass event as its parameter . Now , here the problem what if i want take some other parameter , to overcome this problem we have to wrap the function (can be accomplished by anonymous function or some other defined function in the code ) -> this step you did the correct but thing you did wrong is that you did not accounting the onClick callback default parameter i.e event . so you must account the event parameter in your wrapping function , then you can able to access the event object.
I hope so you get the answer.
{data.map((e) => ( <li key={e._id}> <button
onClick={(event) => onSubmit(event, e._id)}
className="btnx btn-primary"
>
Book Now logout
</button> </li> )}
checkResult is a helper function which is imported in my component.jsx
component.jsx
return(
<ul>
{options.map((option) => {
return (
<li key={option.value}>
<button
data-testid="unlock-btn"
onClick={() => {
checkResult()
? lunch(option.value)
: showError();
}}
>
{option.label}
</button>
</li>
);
})}
</ul>;
)
my test
import * as helper from "../helpers/checkResult";
it("fires action when lunch is clicked", async () => {
const spy = jest.spyOn(helper, 'checkResult');
let component;
await act(async()=>{
component = <component /> ;
})
await expect(screen.queryByTestId("unlock-btn"));
fireEvent.click(screen.queryByTestId("unlock-btn"));
expect(spy).toHaveBeenCalled();
});
this is the error i'm getting
Unable to fire a "click" event - please provide a DOM element.
i have also provided my getComponent Method above
You're not providing options to the component so it has nothing to render. You're also using a map to render a list of items all of which have the same id. You should do something like
map((option, index) => {
return (
<li key={option.value}>
<button
data-testid=`unlock-btn-${index}`
This way you can target each individual option by ID in your test.
Edit: Your fireEvent is not defined in your example either.
The right way would be using the aria-label and attributes to be able to select those buttons without the need of data-testid.
<button
onClick={() => { checkResult() ? lunch(option.value): showError();}}
name={option.label} // assuming the labels are unique
>
{option.label}
</button>
then:
import React from 'react';
import { render, screen, fireEvent } from '#testing-library/react';
it('Should do some test', ()=>{
render(<MyComponent/>)
const button = screen.getByRole('button', {name: "some-label"})
fireEvent.click(button)
expect(....).toBe(...)
}
I am working on app using react,
const getButtonId=(num)=>{
let click_detect=document.getElementById('div_'+num)
console.log(click_detect)
}
this.state.users.map(i=>{
return(
<button id={'div_'+i.id} onClick={(i.id)=>this.getButtonId(i.id)}>
Click Me
</button>
)
})
So every time I clicked on the button, I kept getting null. Why is that? If I want all buttons to have different id, What should I do here?
Try this:
const getButtonId = (id) => console.log("Button ID:", id);
this.state.users.map((user, index) => (
<button key={index} onClick={() => this.getButtonId(user.id)}>
Click Me
</button>
))
I made a code sandbox example for my problem: https://codesandbox.io/s/react-form-submit-problem-qn0de. Please try to click the "+"/"-" button on both Function Example and Class Example and you'll see the difference. On the Function Example, we always get the previous value while submitting.
I'll explain details about this example below.
We have a react component like this
function Counter(props) {
return (
<>
<button type="button" onClick={() => props.onChange(props.value - 1)}>
-
</button>
{props.value}
<button type="button" onClick={() => props.onChange(props.value + 1)}>
+
</button>
<input type="hidden" name={props.name} value={props.value} />
</>
);
}
It contains two buttons and a numeric value. User can press the '+' and '-' button to change the number. It also renders an input element so we can use it in a <form>.
This is how we use it
class ClassExample extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 1,
lastSubmittedQueryString: ""
};
this.formEl = React.createRef();
}
handleSumit = () => {
if (this.formEl.current) {
const formData = new FormData(this.formEl.current);
const search = new URLSearchParams(formData);
const queryString = search.toString();
this.setState({
lastSubmittedQueryString: queryString
});
}
};
render() {
return (
<div className="App">
<h1>Class Example</h1>
<form
onSubmit={event => {
event.preventDefault();
this.handleSumit();
}}
ref={ref => {
this.formEl.current = ref;
}}
>
<Counter
name="test"
value={this.state.value}
onChange={newValue => {
this.setState({ value: newValue }, () => {
this.handleSumit();
});
}}
/>
<button type="submit">submit</button>
<br />
lastSubmittedQueryString: {this.state.lastSubmittedQueryString}
</form>
</div>
);
}
}
We render our <Counter> component in a <form>, and want to submit this form right after we change the value of <Counter>. However, on the onChange event, if we just do
onChange={newValue => {
this.setState({ value: newValue });
this.handleSubmit();
}}
then we won't get the updated value, probably because React doesn't run setState synchronously. So instead we put this.handleSubmit() in the second argument callback of setState to make sure it is executed after the state has been updated.
But in the Function Example, as far as I know in state hooks there's nothing like the second argument callback function of setState. So we cannot achieve the same goal. We found out two workarounds but we are not satisfied with either of them.
Workaround 1
We tried to use the effect hook to listen when the value has been changed, we submit our form.
React.useEffect(() => {
handleSubmit();
}, [value])
But sometimes we need to just change the value without submitting the form, we want to invoke the submit event only when we change the value by clicking the button, so we think it should be put in the button's onChange event.
Workaround 2
onChange={newValue => {
setValue(newValue);
setTimeout(() => {
handleSubmit();
})
}}
This works fine. We can always get the updated value. But the problem is we don't understand how and why it works, and we never see people write code in this way. We are afraid if the code would be broken with the future React updates.
Sorry for the looooooooong post and thanks for reading my story. Here are my questions:
How about Workaround 1 and 2? Is there any 'best solution' for the Function Example?
Is there anything we are doing wrong? For example maybe we shouldn't use the hidden input for form submitting at all?
Any idea will be appreciated :)
Can you call this.handleSubmit() in componentDidUpdate()?
Since your counter is binded to the value state, it should re-render if there's a state change.
componentDidUpdate(prevProps, prevState) {
if (this.state.value !== prevState.value) {
this.handleSubmit();
}
}
This ensure the submit is triggered only when the value state change (after setState is done)
It's been a while. After reading React 18's update detail, I realize the difference is caused by React automatically batching state updates in function components, and the "official" way to get rid of it is to use ReactDOM.flushSync().
import { flushSync } from "react-dom";
onChange={newValue => {
flushSync(() => {
setValue(newValue)
});
flushSync(() => {
handleSubmit();
});
}}
Hi I have this component named "ConfirmSave". I have certain condition before I show this component
{FormStatus.statusMode === "Success" && (
<ConfirmSave FormStatus={FormStatus} />
)}
Inside this component I have this
const ConfirmSave = () => {
return ( <div className="col">
<a
className="btn confirm-btn yes-sign col"
onClick={console.log("TEST")} ) > test</a></div>
}
My problem is, even the link is not yet click the "onClick" its activating, it saying TEST in my log
Oh i am calling the function not the trigger
() => { this.props.removeTaskFunction(todo)