I am trying to call a function after the button has been clicked, which is possible so far but I have problems in passing the argument.
This is my first React App so bear with me.
In the this part the onClick event calling the "clickedQuickreply()" wont work
It fires a "TypeError: Cannot read property 'value' of undefined"
export function showMessage() {
console.log("Show Message");
let timeStamp = messages.giveTimestamp("not set");
let listItems = messageList.map(d => (
<p className={d.senderId} key={d.senderId}>
{" "}
{d.text}{" "}
</p>
));
let listreply = quickReplyList.map(d => (
<button
className="quickReplyButton"
key={d.id}
value={d.qrText}
**onClick={clickedQuickreply(this.value)}**
>
<span> {d.qrText} </span>
</button>
));
return (
<div>
<div className="timestamp">{timeStamp}</div>
<ul>{listItems}</ul>
<div className="quickreply">{listreply}</div>
</div>
);
}
export function clickedQuickreply(e) {
console.log("Clicked", e);
quickReplyList.length = 0;
//send.sendMessageToServer(query);
}
This is the code where it renders. Named App.js "main"
Normally I wanted to do the re-rendering everytime a fetch Request has completed, but my React understanding is not that far I guess.
class MessageDisplay extends React.Component {
constructor(props) {
super(props);
this.state = null;
}
componentDidMount() {
window.addEventListener("click", this.tick.bind(this));
window.addEventListener("keypress", this.tick.bind(this));
}
componentWillUnmount() {
window.removeEventListener("click", this.tick.bind(this));
window.removeEventListener("keypress", this.tick.bind(this));
}
componentDidUpdate() {}
tick() {
this.forceUpdate();
}
render() {
setTimeout(() => {
this.forceUpdate();
}, 2000);
return (
<div className="chatBox">
<ui.showMessage />
</div>
);
}
}
So how do you pass an argument in that situation for example?
Thanks for your time and patience.
You should write onClick={clickedQuickreply(this.value)} as onClick={clickedQuickreply}. React will execute the function by passing it the event object as argument internally.
One more thing I notcied here is that, you no need to export the function clickedQuickreply, as it can be private used as callback function as you did now by attaching it with the onClick props. So write it without export and define it inside the showMessage function.
Related
My question is regarding the flow of an onClick event in React when clicking a div.
My application has a ParentComponent which calls in to a ChildComponent and subsequently creates a div for each member of the props.options array in the ParentComponent.
I have two questions which are as follows:
When I click the div, how can I pass the onClick event to this component?
How does the div know which option created it? I mean to ask, some iteration of the this.props.options array, say, optionA created, say, divA, how does divA know that it was created by optionA and not optionB? Is this done by React internally?
This is my Parent component
interface ParentComponentState {
..
..
}
export interface ParentComponentProps {
...
...
}
export class ParentComponent extends React.Component<ParentComponentProps, ParentComponentState> {
public state: ParentComponentState = {
...
};
constructor(props) {
super(props);
}
private handleClick = (item) => {
console.log(item);
}
public render(): JSX.Element {
return (
<>
<SomeButtonComponent>
{ this.props.options.map((item: any, index: any) => (
<ChildComponent
onClick={ () => this.handleClick(item) }
/>
)) }
</SomeButtonComponent>
</>
);
}
}
This is my Child component
export function ChildComponent(props: IChildComponent): JSX.Element {
return
(
<div
ref={ ... }
className={ someClassName }
dangerouslySetInnerHTML={ { __html: someHTML } }
onClick={ props.onClick }
/>
)
}
for your first question about passing event you can do this:
export class ParentComponent extends React.Component<ParentComponentProps, ParentComponentState> {
public state: ParentComponentState = {
...
};
constructor(props) {
super(props);
}
private handleClick = (item) => (event) => { // This is called function currying
console.log(item);
console.log(event);
}
public render(): JSX.Element {
return (
<>
<SomeButtonComponent>
{ this.props.options.map((item: any, index: any) => (
<ChildComponent
onClick={ this.handleClick(item) }
/>
)) }
</SomeButtonComponent>
</>
);
}
}
and for your second question if you want to know in ChildComponent that which options created it you have to pass another props to ChildComponent and send the option in ChildComponent as a prop and use it there
I would try to answer your questions to the best of my ability, so here it is:
Who controls the order of arguments in the invocation of this call?
You Do, React Only Says give me function which takes an argument and When an event for example click event happened I will call your function with and will send the event object as the parameter of it.
so it's on you, if you want to have more arguments you need to some how get around this by currying arguments or binding them like below:
handleClick = (item) => (event) => {
console.log(item);
console.log(event);
}
when you doing something like this and then in the onClick props you're calling the handle click like below:
<ChildComponent onClick={ this.handleClick(item) } />
you're actually sending
(event) => {
console.log(item);
console.log(event);
}
to your props and this is what React wants(A function which takes an argument and will call it when event happpens)
See Event Handling in React Docs
How does the browser know to pass in only the second argument as the actual event?
As I said above, React has its own Event System on top of browser Event System (Read about it here),
so the answer to this question is : it doesn't, React only needs a function with on parameter( For better understanding of the work around you need know about javascript closure in case you want to use currying or javascript bind function in case you're using binding )
Where is the contract for it?
you define in your code
Does the onClick function in the div expect a callback function where the second argument is the actual event?
No, It just need a function with one parameter, and in case it's confusing to you when using bind function, just read bout it a little here
Where is this defined?
it's one of the class parameter, and you need to read about it until you understand it
(I recommend using Function Components so you don't need to work with this concept in javascript)
Good morning community, I have a question. I am working with react js and I have to pass a function through props to a child component. The question is that this function is not going to be directly associated with a click, but I must use it but applying some logic in the child component and in case the condition is fulfilled launching said function passed by props. Can what I say be done or always the function that passes by itself must be associated with an arrow function and a given event?
export default father extends Component{
const fun = () => {
console.log("hello")
}
render(){
return(
<Child fun = {this.fun} />
)
}
export default child extends Component{
this.state = {
count : 1
}
const thing = () => {
const { count } = this.state
if(count == 1){
this.props.fun
}else{
console.log("is not 1")
}
}
render(){
return(
<Button onPress = {() => this.thing()} />
)
}
}
It's a pretty bad example but it's something similar to what I want to do
Yes, what you have written can be done. The function that you pass down as props can be executed conditionally, as an event handler, or not at all. Once you pass it as props it is completely up to you how you want to use it.
I'm trying to just test that a function is indeed invoked when a click action occurs on a link in my component. I keep receiving the error
Expected mock function to have been called, but it was not called.
But it works correctly in the browser.
I thought maybe there was an issue with the test finding the id I was asking it to look for, but using other methods I see it was able to access the element just fine.
The component
import { toggleEditMode } from './otherFile.js'
class PersonalInformation extends Component {
constructor(props) {
super(props);
this.state = {editMode: false}
this.toggleEditMode = toggleEditMode.bind(this);
}
render(){
const { editMode } = this.state;
return(
<div>
{!editMode &&
<div className="col-md-4 hidden-sm-down">
<a
id="editingToggleButton"
className="display-block"
role="button"
href="javascript:void(0);"
onClick={() => this.toggleEditMode()}
>
<span className="icon icon-sm dls-icon-edit" />
<span className="pad-1-l">Edit</span>
</a>
</div>
}
</div>
)
}
}
The toggleEdit method
export function toggleEditMode() {
this.setState({ editMode: !this.state.editMode })
}
The test
describe('edit', () => {
it('should switch to editMode with click', () => {
const toggleEditMode = jest.fn();
const wrapper = mount(
<PersonalInformation
toggleEditMode={toggleEditMode}
/>
);
wrapper.find('#editingToggleButton').simulate('click');
expect(toggleEditMode).toHaveBeenCalled();
});
}
I was able to log what it finds when using the find method and it returns the right element. But I can't seem to figure out how "it was not called".
In the test file you have assigned the mock function to the props but in the component you are using it as a class function.
So, in the test file, when the user clicks the HTML element it fires the class function and not the mocked one.
Essentially, I want to invoke a callback passed down from a parent component then reassign a value. I've tried creating a class method that invokes the given callback function from the parent components props, but I'm getting an infinite loop with setState. On another method that I tried but cannot seem to replicate at the moment, an error was thrown that stated "callback is not a function".
Perhaps, I'm phrasing this in a weird way. Here's an example:
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = { parentState: true }
this._handleToggle = this._handleToggle.bind(this);
}
_handleToggle() {
this.setState({ parentState: !this.state.parentState })
}
render() {
return (
<ChildComponent
onSomeEvent={this._handleToggle}
/>
)
}
}
class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.randomInteger = 8;
this._invokeCallback = this._invokeCallback.bind(this);
}
// this is where I'm having trouble
_invokeCallback(callback) {
callback();
this.randomInteger = 0;
}
render() {
const { onSomeEvent } = this.props;
// Error
return (
<button onClick={this._invokeCallback(onSomeEvent)} />
)
}
}
What I want from here is to reassign this.randomInteger to a certain value AFTER invoking the callback that was handed down from the parent component. What can I do from here?
I apologize if my example is missing some pieces or is incomplete. I am rushing to write this up. Please feel free to correct any mistakes I made in my phrasing or example code. Thanks in advance.
Your _invokeCallback is executing immediately.
Due to the parentheses and passing an argument here this._invokeCallback(onSomeEvent), you are setting onClick to the result of the _invokeCallback method.
This is what is causing the infinite loop where setState in the parent causes a re-render in the child which then executes _invokeCallback again, and so on.
You could use an anonymous function with onClick so that _invokeCallback is only executed when the button is clicked:
render() {
const { onSomeEvent } = this.props
return (
<button onClick={ () => this._invokeCallback(onSomeEvent) } />
)
}
Alternatively, you could call the onSomeEvent function from the _invokeCallback method:
_invokeCallback() {
this.props.onSomeEvent()
this.randomInteger = 0
}
render() {
return (
<button onClick={ this._invokeCallback } />
)
}
I have code:
var React = require('react');
class MasterLayout extends React.Component {
constructor(props) {
super(props);
console.log("I am constructor");
this.getComponent = this.getComponent.bind(this);
this.testMethod = this.test.bind(this);
this.testMethod();
}
test() {
console.log("test method called");
}
getComponent(ev) {
console.log('li item clicked!');
event.currentTarget.style.backgroundColor = '#ccc';
}
render() {
return (
<div>
<h3 id={this.props.id} onClick={this.getComponent}>qqqqqqqqqqqqqqqqqqqq</h3>
</div>
)
}
};
module.exports = MasterLayout;
When I run node server and go to localhost page, page is rendered sucesfully without any errors.
After click on h3 element nothing happens.
When is pagge loaded i am getting in console:
I am constructor
test method called
After click on h3, nothing happens. Whats wrong is with my code?
EDIT:
onclick="console.log('The link was clicked.'); return false"> too NOT working.
<h3 id={this.props.id} onClick={this.onClick}>CLICK ME</h3>
Unless I'm missing something you don't have an onClick method in MasterLayout
Are you sure you don't mean to create an onHeaderClicked (example) method in MasterLayout, bind it in the constructor, and use that instead of this.onClick?
Change your test() method to be named onClick():
var React = require('react');
class MasterLayout extends React.Component {
constructor(props) {
super(props);
console.log("I am constructor");
this.getComponent = this.getComponent.bind(this);
this.testMethod = this.test.bind(this);
this.testMethod();
}
onClick() {
console.log("test method called");
}
getComponent(ev) {
console.log('li item clicked!');
event.currentTarget.style.backgroundColor = '#ccc';
}
render() {
return (
<div>
<h3 id={this.props.id} onClick={this.onClick}>CLICK ME</h3>
</div>
)
}
};
module.exports = MasterLayout;
or if you are trying to invoke the getComponent() method change it in your render code to use that:
render() {
return (
<div>
<h3 id={this.props.id} onClick={this.getComponent}>CLICK ME</h3>
</div>
)
}
Or if you want to invoke both, call the 2nd method in the first method call function block:
getComponent(ev) {
console.log('li item clicked!');
event.currentTarget.style.backgroundColor = '#ccc';
this.onClick();
}
Nothing happens when you click on h3 because after you click you will get an error that cannot read property currentTarget of undefined as you are receiving the event parameter as ev and using it as event
You need to modify your getComponent method to
getComponent(ev) {
console.log('li item clicked!');
ev.currentTarget.style.backgroundColor = '#ccc';
}