This is an example of something I'd like to understand better syntactically in JSX.
Problem:
This works:
<button
onClick={ !isRecording ? beginRecording : endRecording } >
</button>
and this works:
<button
onClick={ () => { modalPortal.current.open() } } >
</button>
<Modal ref={modalPortal}>
<h1>Congratulations!</h1>
<p>If this modal opened, you find javascript syntax seamless and intuitive</p>
</Modal>
Together, no bueno.
<button
onClick={!isRecording ? () => {modalPortal.current.open();beginRecording} : endRecording } >
</button>
Error:
react-expected-an-assignment-or-function-call-and-instead-saw-an-expression
Detail:
This is inside a function component. isRecording & endRecording etc are are states in an object within the scope of the function component which defines the page I'm on in the app, modalPortal is a reference:
export default function RecordPage()
{
let [audioURL, isRecording, beginRecording, endRecording, timer] = RecorderContext();
const modalPortal = useRef(null);
...
}
I've also tried various permutations of passing this out to a single function that does the conditional evaluation etc
onClick={ doManyThings() } >
With and without arrows, both kinds of brackets and passing in arguments and without, none of it seems to work. I'd love a clear answer from someone knowledgeable!
References to things I've tried that don't work:
Conditional onClick from ternary
Call multiple functions onClick ReactJS
Setting conditional onClick behaviour in React Component
React: Expected an assignment or function call and instead saw an expression
You can move the ternary/branching logic into a single callback function.
<button
onClick={() => {
if (!isRecording) {
modalPortal.current.open();
beginRecording();
} else {
endRecording();
}
}
>
...
</button>
If you want to continue using the ternary though you need to also invoke the beginRecording function. The idea is similar here, based on the condition, return an anonymous function that does a couple things, or return a function reference that does whatever it does.
<button
onClick={!isRecording
? () => {
modalPortal.current.open();
beginRecording(); // <-- also invoke
}
: endRecording
}
>
...
</button>
Try this:
const handleButtonClick = () => {
if (isRecording) {
endRecording()
return
}
modalPortal.current.open()
beginRecording()
}
<button onClick={handleButtonClick} />
Related
i am working on a project with a react.js FE, a Node/Express.js BE and a database. I am currently working on a function which trigger my delete Route in BE. But my function trigger with every load and onlick, but should only trigger onClick.
Here are code samples of my service and my FE component. I am new to react.js so help would be apprechiated.
hardwareService.js:
static deleteHardware(hardwareId) {
console.log(hardwareId);
return axios.delete(hostname + '/hardware/' + hardwareId)
.then(response => {
return response;
})
}
component:
deleteOnClick = (id) => {
console.log('handleDelete wird ausgeführt!' + id);
HardwareService.deleteHardware(id);
}
html:
<tbody>
{this.state.hardware.map(hardware => (
<tr key={hardware.id}>
<td>{hardware.id}</td>
<td>{hardware.producer}</td>
<td>{hardware.model}</td>
<td>{hardware.type}</td>
<td>{hardware.serial_number}</td>
<td>{hardware.price}</td>
<td>{<Button variant="primary">Bearbeiten</Button>}</td>
<td>{<Button variant="primary" onClick=
{this.deleteOnClick(hardware.id)}>Löschen</Button>}</td>
</tr>
))}
</tbody>
Replace this line:
onClick={this.deleteOnClick(hardware.id)}>Löschen</Button>}
With this:
onClick={() => this.deleteOnClick(hardware.id)}>Löschen</Button>}
Explanation: in your current code you are calling the function immediately (when rendering the component) then passing the result as an event handler which has no effect. So you need to encapsulate the function call in another function for future call (arrow functions are well suited for that).
The hardware.id parameter will be enclosed in that function thanks to the JavaScript closure mechanism.
I have this piece of code.
Where the problem I am facing is that is missing a prop which I want to be an id, obtained inside the map function.
Since I am unable to find a way to send the id to the component outside map, I figured I would do this:
This is my render function
render() {
var users = this.state.userList;
const Table = Reactable.Table,
Td = Reactable.Td,
Tr = Reactable.Tr;
if (users.length === 0) {
return <p>loading</p>
}
return (
<div class="maincontainer">
<div className="content-landing">
<Table
className="table"
filterable={['Email']}
itemsPerPage={8}
currentPage={0}
sortable={true}
>
{users.map((row) => {
return (
<Tr className={row.className}>
<Td column="Email">{row.email}</Td>
<Td column="Edit" ><FontAwesomeIcon className="editIcon" onClick={this.showModal(row.id)} icon={faEdit} /></Td> //----THIS.SHOWMODAL IS BEING AUTOEXECUTED WITHOUT ACCOUNTING FOR THE CLICKING
</Tr>
)
})}
</Table>
<EditUserModal show={this.state.showModal} close={this.closeModal} row={this.state.rowId}/> //---I WANT THIS TO RECEIVE A row.id FROM THE ABOVE MAP
</div>
</div>
)
}
I have written a couple comments in the parts where I want to make the changes.
I also thought about putting <EditUserModal> , inside the <Td> , but since its an external npm module it crashes, it only admits text.
So my solution was, to pass the row.id to the showModal function, and try to set is a state from there.
showModal(rowId) {
// console.log("showmodal state before any click")
// console.log(this.state.showModal)
console.log("triggered show modal")
console.log(rowId)
this.setState({
showModal: true,
rowId: rowId
}, () => {
// console.log("clicked show modal")
// console.log(this.state.showModal)
});
}
I think it should work, but since the function has a () , it auto executes without waiting for any click, making my app to crash.
In your code you are executing the function directly: this.showModal(row.id).
You have to use a callBack function to pass row.id something like:
onClick={()=> this.showModal(row.id)}
This should solve your problem.
You can use a callBack function in the onClick like this:
onClick={()=> this.showModal(row.id)}
Or you can define the showModal function like this:
showModal = (rowId) => () => {
...
}
and onClick={this.showModal(row.id)}
For people who does not understand arrow functions, the above solution is similar to this:
function showModal(rowId) {
return function () {
...
}
}
The showModal function returns another function that will be triggered in the onClick event.
I have an svg button that contains children elements(polygons). The handleMouseLeave function is used to set the state and then utilize its callback to update the children immediatley after. Even though the 'mouseleave' and 'callback' logs both fire in order, the rest of the code inside the callback area does not always fire.
Is there a better or correct way to handle the callback?
handleMouseLeave = (e) => {
console.log('mouseleave')
const polygons = [...e.target.children];
this.setState({
translate: "translateX(-100%)",
opacity: 0
}, () => {
console.log('callback')
polygons.forEach(child => {
child.style.transform = this.state.translate;
child.style.opacity = this.state.opacity;
});
});
};
--
render() {
return(
<button>
<HeroButtonSVG
id="HeroButton"
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
/>
<span>Check out my work<i className="fas fa-chevron-right"></i></span>
</button>
);
};
This seems to be an event binding issue, as class methods are not bound by default.
To solve this, you can add the following to the render function, which will bind the event, through using arrow functions to automatically bind:
<HeroButtonSVG
id="HeroButton"
onMouseEnter={e => this.handleMouseEnter(e)}
onMouseLeave={e => this.handleMouseLeave(e)}
/>
It turns out that the actual issue was derived from the pointer-events on the child SVG's. The issue was not related to React's setState callback function.
I tracked the issue here: https://github.com/facebook/react/issues/4492
UPDATE:
Here is a better example;
My code is
let myFunction = () => {
console.log('Yo');
alert('Yo');
}
let About = {
render : async () => {
return /*html*/`
<h1> About </h1>
<button id="myBtn" type="button" >Try it</button>
<script>
document.getElementById("myBtn").addEventListener ("click", ${myFunction})
</script>
`
}
}
export default About;
This transforms to the HTML code;
<div id="page_container" class="container pageEntry">
<h1> About </h1>
<button id="myBtn" type="button">Try it</button>
<script>
document.getElementById("myBtn").addEventListener ("click", () => {
console.log('Yo');
alert('Yo');
})
</script>
</div>
However on clicking on the button, nothing happens;
I am trying to work on a basic vanilla js SPA and I have hit a problem where I am unable to call any functions in my current module from the html code. I am using the es6 modules by specifying in my index.html that script tag is of type="module".
For example, in this code, i have tried both the inline onclick tag attribute as well as adding an event listener (i used one at a time, not together. showing it here just for illustration)
let myFunction = () => {
console.log('Yo');
alert('Yo');
}
let About = {
render : async () => {
return /*html*/`
<h1> About </h1>
<button id="myBtn" type="button" onclick="${myFunction}">Try it</button>
<script>
document.getElementById("myBtn").addEventListener ("click", myFunction()})
</script>
`
}
}
export default About;
and I consume the resultant view as
content.innerHTML = await page.render();
from my main module.
The only way I am able to do this is by having my function call return yet another template containng the actual JS code.
let myFunction = () => {
return `
alert('Yo');
document.getElementById('myBtn').textContent = 'Duh'
`
}
however, this creates a very ugly page where my entire JS code is added inline into the HTML and that I can no longer use double quotes in my js code.
Here's how you can invoke a function in a template literal:
const func = () => 'Hello'
console.log(`${func()} World`)
Figured out my problem with the help of another forum.
"Scripts inserted into innerHTML don't run. You should try splitting the render function into render and onMount - the second one called just after the innerHTML line."
Architecting my app into;
let About = {
render : async () => {
let view = /*html*/
`
<h1> About </h1>
<button id="myBtn" type="button" >Try it</button>
`
return view
},
after_render: async () => {
document.getElementById("myBtn").addEventListener ("click", () => {
console.log('Yo')
alert('Yo')
})
}
}
export default About;
and consuming it as;
content.innerHTML = await page.render();
await page.after_render();
solved my problems.
You can give the onClick a reference to your function, by not providing the () when referencing it. This will tell JavaScript to call the function and attempt to pass it the event's arguments when it gets triggered.
onclick=`${myFunction}`
will get called everytime the element is clicked.
I am new to react.I have a scenario - To use one common popup.
CommonPopup.js
<ButtonWrapper>
<Button secondary onClick={props.onRequestYes}>Yes</Button>
<Button onClick={props.onRequestNo}>No</Button>
</ButtonWrapper>
Now I need to used this common popup in two different components.
Component 1 - Use the popup and call the parent component function and do some action which is working fine.
<CommonPopup
open={this.state.showConfirmCancelOrderPrompt}
onRequestNo={this.togglePopup}
onRequestYes={this.props.cancelOrder}
/>
Component 2 - Use the popup and On Click of "Yes" button , Navigate to a URL with
href={${someURL}?employeeNumber=${employeeNumber}}
Note: Data - someURL and employeeNumber will be passed through context
How could I make use of my component in both the scenarios ?
Have you tried this ?
<MyButton to="user" />
class MyButton extends React.Component{
render() { return <Link to={this.props.to} />; }
}
Try setting window.location = <your url> in the function called by onClick. That should do the trick.
Alternatively, use window.open(<your url>).
Replace <your url> with the url you want.
Edit: Try something like this:
onClick={this.openUrl}
Then, define the function like this:
openUrl() {
url = this.props.theUrl + "?employeeNumber=" + this.props.theEmployeeNumber;
window.open(url);
}
So the answer is ,
In component 2 ,
<ContentContext.Consumer>
{({ someURL, employeeNumber }) => (
<CommonPopup
open={this.state.showConfirmCancelOrderPrompt}
onRequestClose={this.togglePopup.bind(this)}
onRequestYes={() =>
this.handleSearch(someURL,employeeNumber)}
/>
)}
</ContentContext.Consumer>
and in function :
handleSearch = (someURL, employeeNumber) => {
this.props.history.push(`${someURL}?employeeNumber=${employeeNumber}`);
};