REACT: Call an external js function in a react component [duplicate] - javascript

This question already has answers here:
When should I use curly braces for ES6 import?
(11 answers)
How to export & import custom helpers in JS/React?
(2 answers)
Closed 1 year ago.
Anyone know in reactjs how to be able to call that 'openSideMenu' function which is in the vanilla js file that I imported on the top?

You can't.
The function will be scoped to the module and inaccessible outside it.
Rewrite the module you are importing so it exports the data you need.
A dirty hack would be to:
Load the JS file using a <script> element
Ensure that it sets the function as a global
Access window.thatfunction inside the React app
but that's fiddley and has the usual problems of globals.

To further what Quentin said, you're not doing react in a react-y way. To be clear, it's always going to be harder and more confusing to do stuff the wrong way when dealing with react.
The react way to do what you want is something like this:
function NavBarLogo({onLogoClick}) {
return (
<nav>
<img ... onClick={onLogoClick}/>
<img ... />
</nav>
)
}
Whatever renders NavBarLogo looks something like this:
function NavBarContainer() {
cons [className,setClassName] = React.useState('closed');
const handleLogoClick = () => setClassName(c => c === 'closed' ? 'opened' : 'closed')
return (
<div className={className}>
<NavBarLogo onLogoClick={handleLogoClick}>
... other stuff
</div>
)
}

If you exported your openSideMenu function in your sideMenuFunction.js file as default, then you need to import like this:
import openSideMenu from '../../utils/sideMenuFunction';
if not as default, then you need to import like this:
import { openSideMenu } from '../../utils/sideMenuFunction';
Make sure the names are the same both where you import and from where you import and it will work fine.

When you want to call an external function, you have to export it from the file it's contained in.
So in your example, you would want to have:
import { openSideMenu } from '../../utils/functions.js';
and then in 'functions.js' you would have:
export const openSideMenu = () => {
// Do Stuff Here...
}
And then you'll have no problem calling 'openSideMenu' from your onClick just how you have it

Related

NextJS - ReferrenceError: document is not defined [duplicate]

This question already has answers here:
Window is not defined in Next.js React app
(23 answers)
Closed 1 year ago.
I'm running NextJS v11.1.12, and am trying to run a standard Vanilla JS function that toggles the CSS class of the div with the class "state-select-dropdown-box". My code is:
const Header = () => {
const dropDownMenu = document.querySelector('state-select-dropdown-box');
console.log(dropDownMenu);
function toggleMenu() {
dropDownMenu.classList.toggle('show');
}
return ( <Component /> );
}
When the app compiles, I get "Referrence Error: document is not defined". What's weird is I have got these functions running earlier today with no issues whatsoever and not changing a thing.
After some mass Googling and research, I've come to the conclusion that maybe I'm just not understanding how SSR works in NextJS? Could anyone explain or shine some light on why I'm not achieving the results that I'm expecting and how this can be solved?
You are getting this error because document object is not available on the server. Similarly, if you try to use window, localStorage then also it will throw the error.
These are only available on client-side(browser).
NextJs serves your pages from the server. So in your case it is trying to get document on the server, but document object is not available on the server. Hence you are getting the error.
To get rid of this error:
You need to specify that such code should be run on browser side rather than on the server.
So for this, you can use typeof document
So your code should be like this:
const dropDownMenu = typeof document !== 'undefined' && document.querySelector('state-select-dropdown-box');
Ref: https://github.com/vercel/next.js/issues/5354#issuecomment-520305040
#Surjeet Bhadauriya answer is technically correct, however next.js provide built in functionality to dynamically load components, in fact with next/dynamic you can load a component withoutSSR.
From the docs :
You may not always want to include a module on server-side. For
example, when the module includes a library that only works in the
browser.
const Header = () => {
const dropDownMenu = document.querySelector('state-select-dropdown-box');
console.log(dropDownMenu);
function toggleMenu() {
dropDownMenu.classList.toggle('show');
}
return ( <Component /> );
}
export default Header
Then in your page (or wherever you import it) :
import dynamic from 'next/dynamic'
const DynamicComponentWithNoSSR = dynamic(
() => import('../components/Header'),
{ ssr: false } // <-- not including this component on server-side
)

Confusion with default import of React

To import React we write import React from 'react'.
But this is a default export right ? So if I change its name to something else other than React it should also work. But it doesn't work. Can anyone please explain why?
Essentially, JSX compilers (like Babel/TypeScript) convert the JSX code to pure JavaScript.
For example, the following JSX code:
const Element = () => (
<div>
Hey there
</div>
);
is compiled into:
const Element = () => (
React.createElement("div", null, "Hey there")
);
Which is now valid JavaScript that can be parsed by the browser.
As you may have noticed, it uses the React.createElement function to create the div. This is why changing the name of the import doesn't work - the compiler still tries to use React.
Babel lets you configure this using the pragma option, if desired, allowing you to use a different function name.
TypeScript can do the same using the jsxFactory compiler option.
It works so, as you use Babel, or something similar, to translate JSX.
So when you input something like this:
function AComponent() {
return <div>Hello world</div>
}
You will get the next transpiled code:
"use strict";
function AComponent() {
return React.createElement("div", null, "Hello world");
}
By this reason you should use the definite name of React.
You can try it here: https://babeljs.io/repl#?babili=false&browsers=&build=&builtIns=false&spec=false&loose=false&code_lz=AQ4MwVwOwYwFwJYHsrAIIGEkFsAOKBTKOACgEpgBvAKFBACcC4J7UAeAEwQDcA-ACQIAbIUmAB3JPSEc2Aei59aoAL5A&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=es2015%2Creact%2Cstage-2&prettier=false&targets=&version=7.4.4&externalPlugins=

Write global functions to use in all components in angular

Note : Its not for global variable but for a global common function to perform a functionality on all components
I am working on an angular app where I have around 400 components in different modules, almost all components have one same kind of functionality as mentioned below
There is a sections on many pages which shows a "How to work section" which can be closed by users and will remain closed unless they open it again, I have done it with cookies which I set on click on close or open icon but this function is written in a component and this needs to be imported in other components
I want to create a functions somewhere which perform this functionality on click on icon and can be called without importing any component in others.
One way to do it ( as I thought ) could be create a JavaScript function in a file and load it in index file and then call this function on click on close and open icon
Not sure if this is the best way to do this. Hope someone will come up with a better solution.
1. create your global function service, i.e. 'funcs.services.ts' under 'services' directory:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class FuncsService {
constructor() { }
myGlobalAddFunction(a){
return a++;
}
mySecondFunc(){
// add more... and so on
}
}
2. Import the function in your component:
// your path may different
import { FuncsService } from './../services/funcs/funcs.service';
//...
constructor(
private funcs: FuncsService
) {}
ngOnInit(): void {
let x = 1;
myResult = this.funcs.myGlobalAddFunction(x);
// Then you are expecting 2 for return value
}
3. Hope that works... :)
You can export a function that is a written in .ts file and then call it in all your components.
export function myFunction(){
// Do something
}
And then import the function myFunction() in other components. That works fine for me and can be useful in certain cases
This isn't the best solution (in my opinion). The best solution would be to either create a service, or an utils class.
But if you want to do this, I suggest you make a JS file, that you declare in your angular-cli.json file under the scripts property, containing your functions.
EDIT Now that you've came back to reason, here is a code sample to make utils classes.
export const IMG_UTILS = {
convertPngToJpg = (picture: any) => {
// Your logic here
}
};
export const VIEW_MANAGER = {
isAdblockActive = () => {
// test if an ad-blocker is active
}
};
You can make any utils class you want in a const, then put it into a file. Then, you can put this file in an utils folder, and request it with
import { VIEW_MANAGER } from 'src/app/utils/view-manager';
Otherwise, you can make a service, which is handled by Angular, with a console command such as
ng g s services/view-manager/view-manager
And it will behave the exact same way : you will import it in your components to use it.
Hope this helps !
The most recommended way is to use a service and inject it whenever needed, but there is a way to have a function available globally.
Although I don't think it's a really good idea, you can add the function in the index.html file, then whenever you want to use it, you have to use #ts-ignore to avoid an error from being thrown.
e.g
index.html
<script>
function globalFunc(){
alert(2)
}
</script>
anywhere else on the app
// #ts-ignore
globalFunc();
List item
Just to chime in with possibly a duplicate answer albeit more fleshed out... I have a utilities class which I use.
For example:
export class Utilities {
// Simple promise wrapper for setTimeout. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#creating_a_promise_around_an_old_callback_api
public static Wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
}
The class is referenced in a component via the import statement:
import { Utilities } from 'path/to/Utilities';
And then you can call your static methods thus:
Utilities.Wait(30000)
.then(() => DoStuff())
.catch(() => console.log('Darn!'));
I would tend to use RxJs but I've written it this way to keep things a little cleaner.

render React component from a string

I have some React code in the string, for example:
const component = `
function App() {
return (
<div>
test
</div>
);
}
`;
And I want to be able to render that component from within browser, something like:
import React, { Component } from 'react';
import { render } from 'react-dom';
import * as babel from 'babel-standalone';
const babelCode = babel.transform(component, { presets: ['react', 'es2015'] }).code;
render(eval(babelCode), document.getElementById('WorkFlow'));
This particular example doesn't work but it shows what I'm looking for, any help appreciated!
Thanks!
Babel produces the code with "use strict" and eval() doesn't work with it well. First, we should remove that line manually.
const code = babelCode.replace('"use strict";', "").trim();
Ideally, after this following lines should work.
eval(code);
render(<App/>, document.getElementById('WorkFlow'));
Note that you don't need to put eval() inside render. It doesn't return your App function or anything. Instead, it will add App to context and we can use it after eval() statement.
But usually, React app has a compile step with webpack or similar tool and will complain about undefined App.
As a workaround, we can wrap our component with a Function which returns our component itself. Now we can call this function to get our component. But the context of wrapping function doesn't have React variable. So we have to pass it manually as a parameter. If you are going to use any other variable from the current context, you will have to pass those as well.
const code = babelCode.replace('"use strict";', "").trim();
const func = new Function("React", `return ${code}`);
const App = func(React)
render(<App/>, document.getElementById('WorkFlow'));
Hope this helps!
React will allow you to render either a Component or an Element. You can think of an Element as a raw HTML code in JSX, while a Component is a prototype, which inherits from React.Component. In your code you are trying to render a result of evaluating the babel transpiled code, which will fail (I'm not sure what it is, but it's probably undefined or null). If you want to make it work, first evaluate the code and then invoke the function to pass the Element code to the render function:
eval(babelCode); // now the App function has been defined and you can use it in the code
render(App(), document.getElementById('WorkFlow'));
// ^^ here the App function is being invoked
Old answer (I thought you were trying to pass the component as a file not and not as a variable to transpiler):
babel will never transpile strings, so this is not going to work out for you. You can however consider using a raw JS code instead of JSX as your string content. More about it you can read here: https://facebook.github.io/react/docs/react-without-jsx.html

How to properly import namespaced code used in Webpack/es6/babel?

I'm currently working on a ReactJS project and I'm trying to come up with an effective way to namespace my code. The most obvious solution I have is to do the following:
let API = {
init: function() {
// Do some type of initialization here
}
makeACall: function() {
// Make a call
}
};
Previously, I'd make a file of functions each of which were exported like:
export function makeACall() {
// Make a call
}
And then I'd import it into another file using: import { makeACall } from 'utils/api';
However the problem here is that I may have another function in the imported file called makeACall. So what I'd like to do is namespace it. Question is: how do I import individual functions from an object/namespace or is this not possible?

Categories

Resources