How can I Use Consts from different files in React JS - javascript

Can you please tell me how to use consts from different JS files in React. I'm trying to calculate a total score of 4 different Quiz scores (Average).
Thank you !
I did try to export and import but didn't work.
Here is the code I'm working on for the first quiz :
const playerStatsEco = {
ecoscore: null,
numberOfQuestions: null,
numberOfAnsweredQuestions: null,
correctAnswers: null,
wrongAnswers: null,
};
class playeco extends Component {
...
endGame = () => {
alert('Le quiz est terminé ! لقد انتهى الاختبار');
const { state } = this;
playerStatsEco.ecoscore = state.ecoscore;
playerStatsEco.numberOfQuestions = state.numberOfQuestions;
playerStatsEco.numberOfAnsweredQuestions = state.correctAnswers + state.wrongAnswers;
playerStatsEco.correctAnswers = state.correctAnswers;
playerStatsEco.wrongAnswers = state.wrongAnswers;
setTimeout(() => {
this.props.history.push('/play/sum', playerStatsEco);
}, 1000);
};
When I try to export the class, it works. But when I try to export the const as well using this line
export {playeco, playerStatsEco};
This error happens :
Attempted import error: './components/quiz/playeco' does not contain a default export (imported as 'playeco').

You can export your consts and import them from different files.
// In file where constant declared
export const myConst = "some value";
//In imported file
import {myConst} from "./fileWhereConstDeclared"

You can export them:
export const playerStatsEco = {...}
export class playeco extends Component {...}
then you can import them from outside like that :
import {playerStatsEco, playeco } from "./fileWhereConstDeclared"

Related

React Constants inside a Function

I need help to export the constants. I am getting different errors when i try to search for this on google or other related topics at stackoverflow.
This is my Printer.jsx
import React, { useRef, useState } from "react";
// export individual features (can export var, let,
// const, function, class)
export let ePosDev = new window.epson.ePOSDevice();
export const ePosDevice = useRef();
export const printer = useRef();
export function connectFunction() {
ePosDevice.current = ePosDev;
ePosDev.connect("192.168.1.254", 8080, (data) => {
if (data === "OK") {
ePosDev.createDevice(
"local_printer",
ePosDev.DEVICE_TYPE_PRINTER,
{ crypto: true, buffer: false },
(devobj, retcode) => {
if (retcode === "OK") {
printer.current = devobj;
} else {
throw retcode;
}
}
);
} else {
throw data;
}
}); };
I need to add the const connect to the App.js so that if the App is starting the connection is also starting. The second is that i need to add the const print to ReactB.js-file so if content of ReactB.js-page is loading the print-request should be send.
Thanks for your help! Stuck at this since 5 hours and dont know how to deal with this problems.
It seems your main issue stems around how to export constants. I recommend checking out MDN for more info: https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export
Below is an excerpt on named exports that is relevant to your scenario.
// export features declared earlier
export { myFunction, myVariable };
// export individual features (can export var, let,
// const, function, class)
export let myVariable = Math.sqrt(2);
export function myFunction() { ... };
So for your example, it would just be a matter of adding declaring the const with export const connect = value; or adding export { connect }; after it is declared.

Svelte: How to import all stores from a file without listing them all?

Is it possible to import all exported stores from a file in a single line? Instead of listing them all like so:
import { store1, store2, store3 } from './stores.js';
Is there a way to do something like this:
import { * } from './stores.js';
or is there some other workaround?
If not, what is the recommended architecture to avoid the need for this?
I do not know if it satisfies your needs but you could export all stores in an object
//main.svelte
<script>
import stores from './stores.js';
let count_value, store1_v, store2_v;
stores.count.subscribe(value => {
count_value = value;
});
stores.store1.subscribe(value => {
store1_v = value;
});
stores.store2.subscribe(value => {
store2_v = value;
});
</script>
<h1>The count is {count_value}</h1>
<h1>The count is {store1_v}</h1>
<h1>The count is {store2_v}</h1>
//stores.js
import { writable } from 'svelte/store';
export const count = writable(0);
export const store1 = writable(4565465);
export const store2 = writable(345);
export default {
count,
store1,
store2,
}
Another option for stores would be
//stores.js
import { writable } from 'svelte/store';
export default {
count: writable(0),
store1: writable(4565465),
store2: writable(345),
}

How do I load and run external Javascript code in React that have their definitions in the application and not in the imported file?

Basically, I'm trying to run a function that creates and adds a Recipe class to an array in React based on an external javascript file that is hosted online - but all the definitions are inside my React app.
The external file looks like (Recipes.js) this:
function LoadRecipes(){
AddToRecipes(new Recipe({
name: "Kronyxium Core",
components: [],
requirements: [],
craftedAt: "Frost Temple Smithy"
}));
}
The way I attempt to go on with this follows:
import React, {useState, useEffect} from 'react';
import RecipeManager from "../logic/RecipeManager.js";
const Recipe = RecipeManager.Recipe;
const recipesList = RecipeManager.recipesList;
const AddToRecipes = RecipeManager.AddToRecipes;
function RecipeController() {
const [loadingRecipes, setLoadingRecipes] = useState(true);
useEffect(() => {
const script = document.createElement("script");
script.src = "https://raw.githack.com/Soralei/extern/main/Recipes.js";
script.async = true;
script.onload = () => {
setLoadingRecipes(false);
}
document.body.appendChild(script);
}, []);
useEffect(() => {
if(!loadingRecipes){
window.LoadRecipes();
}
}, [loadingRecipes]);
return (
<div>
{loadingRecipes ? <p>Loading recipes...</p> : (
<>
<p>Recipes:</p>
{/*recipesList.map((a, index) => <p key={"r"+index}>{a.name}</p>)*/}
</>
)}
</div>
)
}
export default RecipeController
Note that I try to run the function using window.LoadRecipes() once the script has been imported. However, I get undefined errors when the function is run:
Recipes.js:3 Uncaught ReferenceError: AddToRecipes is not defined
at LoadRecipes (Recipes.js:3)
I'm also adding the content of RecipeManager.js for clarity. This is local logic, and the goal is to have the external function make use of it:
class Recipe{
constructor(options = {}){
this.name = options.name || "Unnamed Recipe";
this.components = options.components || [];
this.requirements = options.requirements || [];
this.craftedAt = options.craftedAt || "handcrafted";
}
}
const recipesList = [];
function AddToRecipes(Recipe){
recipesList.push(Recipe);
console.log(Recipe.name, "was added to the recipes list.");
}
const exported = {
Recipe: Recipe,
recipesList: recipesList,
AddToRecipes: AddToRecipes
}
export default exported;
Is this not possible, or am I just doing this entirely wrong?
Why am I doing this? The idea is to host the recipes online in a way that allows for other people to easily view, edit, and have the changes affect my app directly, while keeping most of the work in the React app.
You have to export the function to be able to access it.
Default export (only one per file):
function LoadRecipes(){
AddToRecipes(new Recipe({
name: "Kronyxium Core",
components: [],
requirements: [],
craftedAt: "Frost Temple Smithy"
}));
}
export default LoadRecipes; // export
You should import it like this:
import LoadRecipes from 'pathtofile';
Named export (multiple ones):
export function LoadRecipes() {
AddToRecipes(new Recipe({
name: "Kronyxium Core",
components: [],
requirements: [],
craftedAt: "Frost Temple Smithy"
}));
}
export const add (a, b) => a + b; // another one
Import like this (using { }):
import {
LoadRecipes,
add
} from 'pathtofile';
Named exports are useful to export several values. During the import, one will be able to use the same name to refer to the corresponding value. Concerning the default export, there is only a single default export per module. A default export can be a function, a class, an object or anything else. This value is to be considered as the “main” exported value since it will be the simplest to import.
You can read about JavaScript modules here

React: Array.reduce + Object.assign for dynamic hookrouter routes complains re: PascalCase [duplicate]

I am trying to dynamically render components based on their type.
For example:
var type = "Example";
var ComponentName = type + "Component";
return <ComponentName />;
// Returns <examplecomponent /> instead of <ExampleComponent />
I tried the solution proposed here React/JSX dynamic component names
That gave me an error when compiling (using browserify for gulp). It expected XML where I was using an array syntax.
I could solve this by creating a method for every component:
newExampleComponent() {
return <ExampleComponent />;
}
newComponent(type) {
return this["new" + type + "Component"]();
}
But that would mean a new method for every component I create. There must be a more elegant solution to this problem.
I am very open to suggestions.
EDIT:
As pointed out by gmfvpereira these days there is an official documentation entry for this:
https://reactjs.org/docs/jsx-in-depth.html#choosing-the-type-at-runtime
<MyComponent /> compiles to React.createElement(MyComponent, {}), which expects a string (HTML tag) or a function (ReactClass) as first parameter.
You could just store your component class in a variable with a name that starts with an uppercase letter. See HTML tags vs React Components.
var MyComponent = Components[type + "Component"];
return <MyComponent />;
compiles to
var MyComponent = Components[type + "Component"];
return React.createElement(MyComponent, {});
There is an official documentation about how to handle such situations is available here: https://facebook.github.io/react/docs/jsx-in-depth.html#choosing-the-type-at-runtime
Basically it says:
Wrong:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Wrong! JSX type can't be an expression.
return <components[props.storyType] story={props.story} />;
}
Correct:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Correct! JSX type can be a capitalized variable.
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}
There should be a container that maps component names to all components that are supposed to be used dynamically. Component classes should be registered in a container because in modular environment there's otherwise no single place where they could be accessed. Component classes cannot be identified by their names without specifying them explicitly because function name is minified in production.
Component map
It can be plain object:
class Foo extends React.Component { ... }
...
const componentsMap = { Foo, Bar };
...
const componentName = 'Fo' + 'o';
const DynamicComponent = componentsMap[componentName];
<DynamicComponent/>;
Or Map instance:
const componentsMap = new Map([[Foo, Foo], [Bar, Bar]]);
...
const DynamicComponent = componentsMap.get(componentName);
Plain object is more suitable because it benefits from property shorthand.
Barrel module
A barrel module with named exports can act as such map:
// Foo.js
export class Foo extends React.Component { ... }
// dynamic-components.js
export * from './Foo';
export * from './Bar';
// some module that uses dynamic component
import * as componentsMap from './dynamic-components';
const componentName = 'Fo' + 'o';
const DynamicComponent = componentsMap[componentName];
<DynamicComponent/>;
This works well with one class per module code style.
Decorator
Decorators can be used with class components for syntactic sugar, this still requires to specify class names explicitly and register them in a map:
const componentsMap = {};
function dynamic(Component) {
if (!Component.displayName)
throw new Error('no name');
componentsMap[Component.displayName] = Component;
return Component;
}
...
#dynamic
class Foo extends React.Component {
static displayName = 'Foo'
...
}
A decorator can be used as higher-order component with functional components:
const Bar = props => ...;
Bar.displayName = 'Bar';
export default dynamic(Bar);
The use of non-standard displayName instead of random property also benefits debugging.
With the introduction of React.lazy, we can now use a true dynamic approach to import the component and render it.
import React, { lazy, Suspense } from 'react';
const App = ({ componentName, ...props }) => {
const DynamicComponent = lazy(() => import(`./${componentName}`));
return (
<Suspense fallback={<div>Loading...</div>}>
<DynamicComponent {...props} />
</Suspense>
);
};
This approach makes some assumptions about the file hierarchy of course and can make the code easy to break.
I figured out a new solution. Do note that I am using ES6 modules so I am requiring the class. You could also define a new React class instead.
var components = {
example: React.createFactory( require('./ExampleComponent') )
};
var type = "example";
newComponent() {
return components[type]({ attribute: "value" });
}
For a wrapper component, a simple solution would be to just use React.createElement directly (using ES6).
import RaisedButton from 'mui/RaisedButton'
import FlatButton from 'mui/FlatButton'
import IconButton from 'mui/IconButton'
class Button extends React.Component {
render() {
const { type, ...props } = this.props
let button = null
switch (type) {
case 'flat': button = FlatButton
break
case 'icon': button = IconButton
break
default: button = RaisedButton
break
}
return (
React.createElement(button, { ...props, disableTouchRipple: true, disableFocusRipple: true })
)
}
}
Across all options with component maps I haven't found the simplest way to define the map using ES6 short syntax:
import React from 'react'
import { PhotoStory, VideoStory } from './stories'
const components = {
PhotoStory,
VideoStory,
}
function Story(props) {
//given that props.story contains 'PhotoStory' or 'VideoStory'
const SpecificStory = components[props.story]
return <SpecificStory/>
}
If your components are global you can simply do:
var nameOfComponent = "SomeComponent";
React.createElement(window[nameOfComponent], {});
Having a map doesn't look good at all with a large amount of components. I'm actually surprised that no one has suggested something like this:
var componentName = "StringThatContainsComponentName";
const importedComponentModule = require("path/to/component/" + componentName).default;
return React.createElement(importedComponentModule);
This one has really helped me when I needed to render a pretty large amount of components loaded in a form of json array.
Assume we have a flag, no different from the state or props:
import ComponentOne from './ComponentOne';
import ComponentTwo from './ComponentTwo';
~~~
const Compo = flag ? ComponentOne : ComponentTwo;
~~~
<Compo someProp={someValue} />
With flag Compo fill with one of ComponentOne or ComponentTwo and then the Compo can act like a React Component.
Assuming you are able to export * from components like so...
// src/components/index.js
export * from './Home'
export * from './Settings'
export * from './SiteList'
You can then re-import * into a new comps object, which can then be used to access your modules.
// src/components/DynamicLoader.js
import React from 'react'
import * as comps from 'components'
export default function ({component, defaultProps}) {
const DynamicComponent = comps[component]
return <DynamicComponent {...defaultProps} />
}
Just pass in a string value that identifies which component you want to paint, wherever you need to paint it.
<DynamicLoader component='Home' defaultProps={someProps} />
Suspose we wish to access various views with dynamic component loading.The following code gives a working example of how to accomplish this by using a string parsed from the search string of a url.
Lets assume we want to access a page 'snozberrys' with two unique views using these url paths:
'http://localhost:3000/snozberrys?aComponent'
and
'http://localhost:3000/snozberrys?bComponent'
we define our view's controller like this:
import React, { Component } from 'react';
import ReactDOM from 'react-dom'
import {
BrowserRouter as Router,
Route
} from 'react-router-dom'
import AComponent from './AComponent.js';
import CoBComponent sole from './BComponent.js';
const views = {
aComponent: <AComponent />,
console: <BComponent />
}
const View = (props) => {
let name = props.location.search.substr(1);
let view = views[name];
if(view == null) throw "View '" + name + "' is undefined";
return view;
}
class ViewManager extends Component {
render() {
return (
<Router>
<div>
<Route path='/' component={View}/>
</div>
</Router>
);
}
}
export default ViewManager
ReactDOM.render(<ViewManager />, document.getElementById('root'));
👍 You can create a reusable component with a fallback component.
export const StringComponent = (Base, { name, Fallback = undefined, ...rest }) => {
const Component = Base[name];
// return fallback if the component doesn't exist
if (!Component) return <Fallback/>
return <Component {...rest}/>;
};
And call it like this:
import * as Pages from "../pages"
const routes = [
{path: "/", element: "Home" },
{path: "/about", element: "About" },
{path: "*", element: "NotFound" },
]
export function App(){
const Fallback = Pages.NotFound
// render each route using a string as name
return (
<div>
{
routes.map(page =>
StringComponent(Pages, { name: page.element, Fallback })
)
}
</div>
)
}
OBS: Imported Pages needs to be something like this:
import Home from "./home"
import About from "./about"
import NotFound from "./not-found"
export { Home, About, NotFound }
I used a bit different Approach, as we always know our actual components so i thought to apply switch case.
Also total no of component were around 7-8 in my case.
getSubComponent(name) {
let customProps = {
"prop1" :"",
"prop2":"",
"prop3":"",
"prop4":""
}
switch (name) {
case "Component1": return <Component1 {...this.props} {...customProps} />
case "Component2": return <Component2 {...this.props} {...customProps} />
case "component3": return <component3 {...this.props} {...customProps} />
}
}
Edit: Other answers are better, see comments.
I solved the same problem this way:
...
render : function () {
var componentToRender = 'component1Name';
var componentLookup = {
component1Name : (<Component1 />),
component2Name : (<Component2 />),
...
};
return (<div>
{componentLookup[componentToRender]}
</div>);
}
...

Is there any way to get all the exported names from a JavaScript file?

Lets say I have a JavaScript file(lib.js) which exports some classes, functions, etc etc.
export class Employment {
id = "";
startDate = "";
endDate = "";
companyEmailAddress = "";
};
export function HolidayPopupContainer() {
return (<div id="#HolidayPopupContainer" />);
}
export default withStyles(styles)(Button);
export default class DayView extends React.Component {
constructor(props) {
super(props);
this.state = {
readOnly: false
}
};
export const Status = [
"Select Status",
"Pending",
"Approved",
"Rejected",
"All"
]
Now this file is saved as lib.js in one of the folder. As this file has exports, those exported can be imported by other JavaScript files.
Is there a way where we can programmatically find the full list of exports from a JavaScript file.
The expected output should be a list/array/json etc. The output for the above mentioned js file would be
Employment
HolidayPopupContainer
withStyles
DayView
Status
Can Object.keys be of any help here?
To start with, there should only be one default export in a module. If you fix that, and remove one of the default exports - say, you change DayView to a named export, then with
import * as LibNamespace from './lib.js'
you will have a (namespace) object whose properties are the named exports, plus the default property for the default export. For your code, the keys of this object will be
console.log(Object.keys(LibNamespace))
// ['Employment', 'HolidayPopupContainer', 'default', 'DayView', 'Status']
If you want withStyles to be "named", and included in the above instead of default, you'll need to change it to be a named export instead:
const exportedVar = withStyles(styles)(Button);
export { exportedVar as withStyles };
But that's kind of confusing, because it looks like you already have a variable named withStyles in scope there. Maybe call the exported variable something else:
export const buttonResult = withStyles(styles)(Button);
(or whatever you prefer)
As per documentation - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export, there can only be one default export per module.
Apart from above solutions, you can also use dynamic import to get exported names.
// some.js
export const name = "someName";
export class Employment {
id = "";
startDate = "";
endDate = "";
companyEmailAddress = "";
};
export function HolidayPopupContainer() {
return "HolidayPopupContainer";
}
export default class DayView {
constructor() {
}
}
export const Status = [
"Select Status",
"Pending",
"Approved",
"Rejected",
"All"
]
// index.js
const exportedVar = [];
import('./some.js')
.then(module => {
const {default: defaultExport, ...rest} = module;
exportedVar.push(defaultExport.name, ...Object.keys(rest));
console.log(exportedVar);
});
See - https://stackblitz.com/edit/js-yndmc6

Categories

Resources