How do I use custom Javascript in Next js - reactjs

Coming from React, i am really confused. In pages/index.js, suppose I have a button with onClick listener, and clicking on that button will log "you clicked" in the console. How do i implement this? I want that page to be statically generated and also give that button some functionality.
The reason I am having a lot of trouble is because in React tutorials or even in my projects, if i needed some functionality i'd do this:
function handleClick() {
document.body.style.background = "black"
console.log("you clicked") //nothing is logged in console
}
export default function App() {
return(
<button onClick{() => handleClick}>Click Me</button>
)
}
I was gonna use this Next.js to see how state works. But I encountered a different problem. Unless I use inline function in onClick, it doesnt work. If I use a seperate handleClick function, the DOM doens't even show that I had an onclick event. I learned that's because Nextjs is rendered server side, so it doesnt have access to DOM and console etc. Then how do i do this?
I just transitioned from React, and in every tutorial, those guys would use handleClick func or whatever to handle events and stuff. But I couldnt find a solution to do this in Next, how does everyone handle this then? Because pages have interactive buttons right? Are those pages not statically generated then?

You forgot call function handleClick:
<button onClick{() => handleClick()}></button>

the same way you do it in react with your onClick function

Static generation pre-rendering does not change the interactivity of any page, check the following from Next.js documentation :
Each generated HTML is associated with minimal JavaScript code
necessary for that page. When a page is loaded by the browser, its
JavaScript code runs and makes the page fully interactive. (This
process is called hydration.)
https://nextjs.org/docs/basic-features/pages

Related

React don't mount component until needed but don't unmount afterwards in list of components

Say I am building an instant messaging with app with React (I'm not doing that exactly, but this is easier to explain). I have a sidebar with a list of conversations and, when you click one, it is shown on the right (similar to this). I don't want to mount each conversation component until the user clicks it, but I don't want to unmount it, just hide it, when they click on another conversation. How can I do this cleanly? There will never be more than about 30 chats for any user.
You can store the enabled conversations in an array that you use to show, and when you disable a conversation you can just add a hidden prop to it which you pass to the conversation and make it return null. This will make it not render anything but will not unmount it since you have not removed it from the array that handles the display of conversations.
example at: https://codesandbox.io/s/wispy-forest-59bqj
This is a bit hard to answer since you haven't posted the code.
But, theoretically, the best way to approach this problem is to transfer the data from your sidebar component and load it onto the right component on a per-user basis. You don't have to mount each "conversation component".
You can do this by with the boolean hidden property in your markup. React will render as usual and simply pass it along to the html, the browser will then simply not paint it.
const HideMe = ({ isHidden }) => (
<div hidden={isHidden}>
can you see me?
</div>
)
I made an example for you:
https://codesandbox.io/s/elastic-curie-t4ill?file=/src/App.js
reference: https://www.w3schools.com/tags/att_hidden.asp

React route url and view changes but component function still active. Why?

I have an event function that is triggered by a button click. It's purpose is to keep the body position fixed keeping it from scrolling until you click the button again to close/toggle it off.
It works fine but, when I click to another page without toggling it off it is still active. Meaning the new page will not scroll because the body position is fixed.
I am new to React FYI
My code:
bodyFixed(event) {
document.body.classList.add('body-fixed');
}
bodyRelative(e) {
document.body.classList.remove('body-fixed');
}
I am using react-static withRouteData, RouteData, Router and I have no issues on those pages. But, on pages like an article page where the route doesn't change the same way. This is where I am seeing the problem.
Is there something I can wrap it with so that when I click to a new page it goes back to default?
Please first ask if you need more information and I will gladly add more.
Yes, you can call bodyRelative method in componentWillUnmount lifecycle hook to unset the class. Something along those lines:
componentWillUnmount() {
this.bodyRelative()
}

How can I trigger a click on an element inside a child component (that I don't have access to)?

I have installed react-file-base64 into my React JS project and have implemented it like so:
import FileBase64 from 'react-file-base64';
import FileUpload from '../../forms/FileUpload'
...
class MyComponent extends Component {
render() {
return (
<FileUpload buttonText='Upload New Image'>
<FileBase64
multiple={ false }
onDone={ this.changeProfileImage }
/>
</FileUpload>
)
}
}
The code is obviously condensed for brevity.
As you can see, I've wrapped the FileBase64 component inside a custom FileUpload component - to do the old JS/CSS trick of hiding the file upload and triggering it via a different button press.
Given that I do not have direct access to edit the FileBase64 component, since it's been installed by NPM (and will possibly be updated by it in the future), and given that it is not a direct input element but rather a custom component that renders one - how can I trigger a click on the input element rendered by the FileBase64 component, from inside my FileUpload component?
You have a few options.
Reconsider using react-file-base64
This is a pretty minor NPM module, so ask yourself: is it worth using a few dozen lines of someone else's code instead of writing the functionality myself? Open source is amazing and leveraging other people's work can be a lifesaver, but learn to recognize when to lean on it and when not to.
Fork react-file-base64
Fork the original project and add whatever functionality you need to meet your requirements. Ideally do it in a well-written, well-documented way so that you can later open a pull request and contribute back to the project in a meaningful way.
Hack it a bit
It's good to stay inside of React as much as possible, but there are ways around it. You can, for example, still select DOM elements using plain old JavaScript. Remember that stuff? ;P
This would probably work fine - wrap the <FileBase64 /> component in a <div> that you can use to select any nested child <input> elements.
class MyComponent extends Component {
...
onBtnClick() {
this.inputWrapper.getElementsByTagName("input")[0].click();
}
render() {
return (
<FileUpload buttonText='Upload New Image' callback={this.onBtnClick} >
<div ref={(el) => this.inputWrapper = el} >
<FileBase64
multiple={ false }
onDone={ this.changeProfileImage }
/>
</div>
</FileUpload>
)
}
}
I dunno how exactly you're handling <FileUpload /> click callbacks but you get the idea. After a component renders, its DOM elements are laid bare for you to access. The trick is figuring out how to select those elements in the first place, and being careful that you don't break React in the process. But selecting an element and triggering a "click" event is pretty benign.
There are several triggers for this component that maybe suits your needs. Some of them are:
beforeUpload: Triggered before uploading. return true to continue or false to stop uploading.
doUpload: Triggered after the request is sent(xhr send | form submit).
onabort:riggered after you aborting a xhr.
uploadSuccess: Callback when upload succeed (according to the AJAX simply).
If you see the plugin documentation you can be how they work in detail, as well as more different events to interact with your input element inside your FileUpload component.

React-Router v4 - Prevent Transition With Function

I was able to prevent navigation as per the v4 docs, but I'm trying to hook up a function so that I can use a modal instead of an alert.
Function:
abandonForm = (route) => {
this.props.showModal('confirm');
console.log('leaving..');
}
In my page:
<NavigationPrompt when={true} message={(location) => this.abandonForm('confirm')} />
this.props.showModal('confirm') activates the modal successfully, but behind the modal the page still transitions - how can I prevent transition until a button in the modal is clicked?
Browsers only allow navigation cancellation by means of the alert box that you've mentioned. This restriction is motivated by phishing/scamming sites that try to use javascript gimmicks to create user experiences that convincingly mimic something that a browser or the OS would do (whom the user trusts). Even the format of the text shown in the alert box is crafted so that it's obvious that it originates from the site.
Of course, as long as the current URL stays within your app, you have control over it using react-router's history. For example you can do the following on navigation:
allow the navigation without confirmation
immediately navigate back to the previous location, but now with a modal on top
navigate away for real this time when the user clicks on a button in the modal.
The disadvantage of this approach (leaving out the sheer complexity of it) is that the user will not get a confirmation dialog if they try to navigate to a different site entirely.
Use:
this.unBlock = this.props.history.block((location, navigateToSelectedRoute) => {
// save navigateToSelectedRoute eg this.navigateToSelectedRoute =
// navigateToSelectedRoute;
// use this.navigateToSelectedRoute() afterwards to navigate to link
// show custom modal using setState
});
and when unblocking is done then call this.unBlock() to remove the listener.
Documentation here for history api

React Component: Foundation Modal (Reveal) won't open

So I've just started learning React and Redux, so I apologize if this is a very noobish question. But I've emptied my Google quote, and can't find anything that helps me.
My problem is: I work on a site with React, Redux, and Foundation 6. One of my React components have a link, that when clicked, should open a Modal with a specific warning for that link. So I've created a component with my modal markup:
ComponentModal.js:
import React, { PropTypes } from 'react';
const Modal = () => (
<div className="reveal" id="exampleModal1" data-reveal>
<h1>Awesome. I Have It.</h1>
</div>
);
export default Modal;
The component with a link renders some stuff, but basically have a
<a data-open="exampleModal1">Click me for a modal</a>
tag in it's render.
And although inspecting the page confirms that the markup for the modal exists, nothing happens when i click the link.
If I move the popup from the component, and into the DOM, the link works.
Some trial and error shows me, that if i manually run $(document).foundation(); in the console when ComponentModal is rendered, the popup works as intended.
So my question is kinda two questions:
1. How do I, in Redux, run $(document).foundation(); when my ComponentModal is done rendering? Maybe I'm wrong, but I don't have the componentDidMount() method available to me, where it might make sense to make that call?
2. Is this a totally wrong way to go about it?
Hope it's not too confusing and not too dumb a question :)
FYI, this question/solution has nothing to do with REDUX!
The problem is that you're trying to use React AND Jquery to make your page do cool things.
You should really choose one or the other.
$(document).foundation() is a Jquery library.
Instead you should use something like React Foundation which removes the jquery dependency and gives you foundation components built with react.
You can do $(document).foundation() in React inside componentDidMount of the component that has the reval modal or better yet You can do this inside componentDidMount of the top most partent in your app.
componentDidMount in React runs once after all the DOM nodes related to that component is mounted. What $(document).foundation() does, if it runs inside componentDidMount, is that it binds event handlers on the elements that have foundation realated attributes like data-dropdown or data-reveal.
componentDidMount() {
$(document).foundation();
}

Resources