I'm a bit new to React so I may be missing something obvious, but I've used similar ways of rendering HTML from a CMS into a partially React DOM (just the component, everything else is provided via jsp.) I can see the data passing in correctly, but it seems like the ReactDOM.render isn't doing anything. Any idea what I'm missing/doing wrong?
import ReactDOM from 'react-dom';
/**** Component ****/
import FulfillmentInfoDrawer from "REACT_COMPONENTS/dialogs/fulfillmentInfoDrawer/FulfillmentInfoDrawer";
/**** Utilities ****/
import {Helper} from 'REACT_UTILITIES/Helper';
function fulfillmentFlyout () {
Helper.waitForElm('#react-fulfillmentFlyout').then(() =>{
let insertFlyoutDiv = document.getElementById('react-fulfillmentFlyout'),
fulfillmentType = insertFlyoutDiv.dataset.fulfillmenttype,
flyoutOne = Helper.decodeHTMLEntities(insertFlyoutDiv.getElementsByClassName('flyoutOne')[0].outerHTML),
flyoutTwo = Helper.decodeHTMLEntities(insertFlyoutDiv.getElementsByClassName('flyoutTwo')[0].outerHTML),
flyoutTrigger = Helper.decodeHTMLEntities(insertFlyoutDiv.getElementsByClassName('flyoutTwoTrigger')[0].outerHTML);
// console.log('Params',insertFlyoutDiv, fulfillmentType, flyoutOne, flyoutTwo, flyoutTrigger);
if(insertFlyoutDiv && fulfillmentType) {
const getFulfillmentInfoDrawer = () => {
return <FulfillmentInfoDrawer drawerType={fulfillmentType} drawer1Content={flyoutOne}
drawer2Content={flyoutTwo} drawer2Trigger={flyoutTrigger}
oldStyleFlyout={true}/>;
}
console.log('render', getFulfillmentInfoDrawer());
ReactDOM.render(<FulfillmentInfoDrawer drawerType={fulfillmentType} drawer1Content={flyoutOne}
drawer2Content={flyoutTwo} drawer2Trigger={flyoutTrigger}
oldStyleFlyout={true}/>, document.getElementById('react-fulfillmentFlyout'));
}
});
}
window.addEventListener('fulfillmentFlyout:BCC', fulfillmentFlyout);
Related
hoping someone here can help me solve this.
Am trying to build a website through NextJs. One of my pages has some paragraphs and buttons which are styled differently based on states and events. I can get the styling to work as intended when using pure React, and also when using a Global Stylesheet with NextJs; but when I use CSS Modules I cant get it to function as intended.
(Note: I can also get it to work by using a simple ternary like
<h1 className={submitted ? styles.showresult : styles.hideresult}>Correct? {correct}</h1>;
but I have some other scenarios where I need to rely on an multiple ifs and create multiple classes, each with their own styling, so I cant make a simple ternary my final solution.
E.g. this is the file pagex.js
import React from 'react';
import ReactDOM from 'react-dom';
const Pagex = () => {
const [submitted, setSubmitted] = React.useState(false); // whether the submit button was pressed
function calculateScore() {
let correct = 0
let incorrect = 0
//......some scoring logic.....
setSubmitted(true)
}
// function to create a display class based on whether the submit button has been pressed
function displayResult(){
if (submitted === true) {
return "showtheresult"
} else {
return "hidetheresult"
}
}
return (
<section className="results">
<h1 className={displayResult()}>Correct? {correct}</h1>
<h1 className={displayResult()}>Incorrect? {incorrect}</h1>
<button className={displayResult()} onClick={handleMovClick}>An instruction</button>
</section>
</div>
);
};
export default Pagex;
the globals.css file contains
h1.hidetheresult, h3.hidetheresult {
visibility: hidden;
}
h1.showtheresult, h3.showtheresult {
visibility: visible;
}
button.hidetheresult {
border-color: pink;
}
button.showtheresult {
border-color: aqua;
}
Changes when using CSS modules
Add a CSS file in the correct folder with the correct name
(../styles/Pagex.module.css) which contains the same styling shown
above
Additional import in pagex.js import styles from '../styles/Pagex.module.css'
Change reference in the function
within pagex.js
function displayResult(){
if (submitted === true) {
return {styles.showtheresult}
} else {
return {styles.hidetheresult}
}
}
When i do this the '.' in {styles.showtheresult} and {styles.hidetheresult} gets highlighted as an error by vscode with this detail: ',' expected. ts(1005).
Saving the js with a dev server running shows a similar message after trying to compile: Syntax error: Unexpected token, expected "," and the browser shows the same message along with "Failed to compile"
Also tried just passing styles.showtheresult / styles.hidetheresult by removing the curly braces from the displayResult() function. That compiles but nothing happens on the compiled webpage, i.e the class doesnt get updated when the button is pressed and so the styling cant be applied.
Also Tried passing as ${styles.showresult} and ${styles.hideresult} (with `)in the return statement. That also compiles but the page itself gives me an "Unhandled Runtime Error ReferenceError: styles is not defined" message and I cant load the page.
Would highly appreciated if someone could help correct my syntax in the function itself or elsewhere in the code.
Because you asked nicely ;) (just kiddin')
So Next.js is an opinionated framework and uses CSS Modules to enforce component scoped styling.
Basically you define your stylesheet with a name.module.css filename and add regular CSS in it.
.hidetheresult {
visibility: hidden;
}
.showtheresult{
visibility: visible;
}
.btn-hidetheresult {
border-color: pink;
}
.btn-showtheresult {
border-color: aqua;
}
Now to use this, import it like any JS module,
import styles from './styles.module.css'
console.log(styles);
// styles => {
// hidetheresult: 'contact_hidetheresult__3LvIF',
// showtheresult: 'contact_showtheresult__N5XLE',
// 'btn-hidetheresult': 'contact_btn-hidetheresult__3CQHv',
// 'btn-showtheresult': 'contact_btn-showtheresult__1rM1E'
// }
as you can see, the styles are converted to objects and now you can use them
like styles.hidetheresult or styles['btn-hidetheresult'].
Notice the absence of element selector in the stylesheet. That's because CSS Modules rewrite class names, but they don't touch tag names. And in Next.js that is
the default behaviour. i.e it does not allow element tag selectors.
File extensions with *.module.(css | scss | sass) are css modules and they can only target elements using classnames or ids and not using tag names. Although this is possible in other frameworks like create-react-app, it is not possible in next-js.
But you can override it in the next.config.js file. (Beyond the scope of this answer)
There is an article which explains how to override it. - disclaimer: I am the author
Now coming to your use-case, you can do contitional styling like so: (assuming the styles are as per the sample given in the answer)
import React from "react";
import styles from "./styles.module.css";
const PageX = () => {
const [submitted, setSubmitted] = React.useState(false);
const getStyle = () => {
if (submitted) return styles.showtheresult;
else return styles.hidetheresult;
};
const getButtonStyle = () => {
if (submitted) return styles["btn-showtheresult"];
else return styles["btn-hidetheresult"];
};
return (
<div>
<section className="results">
<h1 className={getStyle()}>Correct?</h1>
<h1 className={getStyle()}>Incorrect?</h1>
<button className={getButtonStyle()} onClick={handleMovClick}>
An instruction
</button>
</section>
</div>
);
};
As you add more conditions, the methods do tend to get more complex. This is where the classnames
module comes handy.
import styles from "./styles.module.css";
import clsx from "classnames";
const PageX = () => {
const [submitted, setSubmitted] = React.useState(false);
const headerStyle = clsx({
[styles.showtheresult]: submitted,
[styles.hidetheresult]: !submitted,
});
const btnStyle = clsx({
[styles["btn-showtheresult"]]: submitted,
[styles["btn-hidetheresult"]]: !submitted,
});
return (
<div>
<section className="results">
<h1 className={headerStyle}>Correct?</h1>
<h1 className={headerStyle}>Incorrect?</h1>
<button className={btnStyle} onClick={handleMovClick}>
An instruction
</button>
</section>
</div>
);
};
Here's a CodeSandbox for you to play with:
Im starting with react and im trying to make a horizontal scrolling page. It seems to work just fine except for one thing, of which i'm pretty certain i'm missing some React logic for this.
I use a targetContainer div with in it, several pages (fullscreen) and a Navbuttons class to move it around.
In my code below i use a 'NavButtons' functional component that sets the targetContainers 'left' value.
But when I reload the page with F5, my page stays on set style (e.g. left:-300%) but pageCounter goes back to 0, breaking the nav buttons...
I'm pretty certain its because i'm using the css-style but what's the right/best way to solve this?
import React, { useEffect, useState } from 'react';
const NavButtons = (props) => {
const maxCount = props.maxCount;
const [pageCounter, setPageCounter] = useState(0);
const scrollPrev = function () {
if (pageCounter > 0) {
setPageCounter(pageCounter - 1);
}
}
const scrollNext = function () {
if (pageCounter < (maxCount - 1)) {
setPageCounter(pageCounter + 1);
}
}
useEffect(() => {
props.targetContainer.current.style.left = -((pageCounter) * 100) + 'vw';
}, [pageCounter, props.targetContainer]);
useEffect(() => {
setToZero();
}, []);
const setToZero = function () {
setPageCounter(0);
props.targetContainer.current.style.left = 0;
}
return (
<div className="NavButtons">
<button onClick={scrollPrev}>Prev</button>
<button onClick={scrollNext}>Next</button>
</div>
)
}
export default NavButtons;
Here is a stackblitz,
https://react-zyvu7o.stackblitz.io/
Edit on:
https://stackblitz.com/edit/react-zyvu7o?file=src/components/Navbuttons.js
It 'unfortunately' works normal on stackblits, but not on my localhost... :(
I'm fairly confident this only occurs due to browser caching & hot reloading, which is why it's working in your example and not locally.
Is it possible to run html scripts in a specific React component only, instead of directly in index.html. The script loads a third party barcode scanner, which is only being used in one component, and therefore I want to avoid loading it for every component as this will slow the whole app down.
The npm module can be found here: https://www.npmjs.com/package/dynamsoft-javascript-barcode but there is no documentation on how to import it, only to include it like this:
<script src="https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode#7.2.2-v2/dist/dbr.js" data-productKeys="LICENSE-KEY"></script>
<script>
let barcodeScanner = null;
Dynamsoft.BarcodeScanner.createInstance({
onFrameRead: results => {console.log(results);},
onUnduplicatedRead: (txt, result) => {alert(txt);}
}).then(scanner => {
barcodeScanner = scanner;
barcodeScanner.show();
});
</script>
Here is the React sample provided by Dynamsoft GitHub repository: https://github.com/dynamsoft-dbr/javascript-barcode/tree/master/example/web/react
You can check out Dynamsoft.js and HelloWorld.js to see how to import and use the module:
import Dynamsoft from "dynamsoft-javascript-barcode";
Dynamsoft.BarcodeReader.engineResourcePath = "https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode#7.3.0-v1/dist/";
// Please visit https://www.dynamsoft.com/CustomerPortal/Portal/TrialLicense.aspx to get a trial license
Dynamsoft.BarcodeReader.productKeys = "PRODUCT-KEYS";
// Dynamsoft.BarcodeReader._bUseFullFeature = true; // Control of loading min wasm or full wasm.
export default Dynamsoft;
import Dynamsoft from "../Dynamsoft";
import React from 'react';
class HelloWorld extends React.Component {
...
let reader = this.reader = this.reader || await Dynamsoft.BarcodeReader.createInstance();
...
}
Note: This sample uses 7.3.0-v1. 7.2.2-v2 does not support this usage.
I haven't tried this code but I have done some code like this.You can add script tag like this:
class YourComponent extends React.Component {
loadScript() {
let script = document.createElement("script");
script.src = "https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode#7.2.2-v2/dist/dbr.js";
script.setAttribute("data-productKeys","LICENSE-KEY");
script.type = "text/javascript";
document.head.append(script);
}
componentWillMount() {
if(!YourComponent.bScriptLoaded){
this.loadScript();
YourComponent.bScriptLoaded = true;
}
}
}
This will add script tag in head tag and.And after that you can run your code in component.
I want my code to toggle a person handler, Before it was working but since I split into components, It seem to have broken.
Toggle happens on button click (see inside return statement <
button className={btnClass}
onClick={props.toggler}>Button</button>
Here is my entire cockpit.js file (inside src/components/cockpit/cockpit.js).
import React from 'react';
import classes from './cockpit.css';
const Ccockpit = (props) => {
const assignedClasses = [];
let btnClass = ''
if (props.cocPersonState) {
btnClass = classes.red;
console.log(".......")
}
if (props.cocperson <= 2) {
assignedClasses.push(classes.red)
}
if (props.cocperson <= 1) {
assignedClasses.push(classes.bold)
}
return(
<div className={classes.cockpit}>
<h1> Hi I am react App</h1>
<p className={assignedClasses.join(' ')}>hey </p>
<button className={btnClass}
onClick={props.toggler}>Button</button>
</div>
);
}
export default Ccockpit;
and inside App.js
return (
<div className={classes.App}>
<Ccockpit>
cocPersonState = {this.state.showPerson}
cocperson = {this.state.person.length}
toggler = {this.togglerPersonHandler}
</Ccockpit>
{person}
</div>
)
}
}
and this is my togglerpersonHandler code.
togglerPersonHandler = () => {
const doesShow = this.state.showPerson;
this.setState({
showPerson: !doesShow
});
}
I can't see to figure out that why it won't toggle and console.log/change color to red (It isn't changing the state). Can someone please review and figure out the mistake?
Your JSX still isn't right. Please review the JSX syntax with regards to giving it props/children.
You have this:
<Ccockpit>
cocPersonState = {this.state.showPerson}
cocperson = {this.state.person.length}
toggler = {this.togglerPersonHandler}
</Ccockpit>
But those values aren't children, they're properties. So they need to be in the opening tag, like this:
<Ccockpit
cocPersonState = {this.state.showPerson}
cocperson = {this.state.person.length}
toggler = {this.togglerPersonHandler}/>
Revisit some React tutorials to see how JSX should be structured and how it works.
I have scirpt for mobile multilevel menu. How can I get it work in react? I have something like this:
export function mobileNavigation() {
let navElements = document.querySelectorAll('.nav');
let backButton = document.querySelector('.back-nav');
navElements.forEach(el => {
el.addEventListener('click', itemClicked)
})
//more code
}
Then in my mobilenav component i have:
componentDidMount() {
mobileNavigation();
}
But it doesnt work.. I mean I know why but I don't know how to solve it. How can I get my script available the whole time not only once when component mounts?
import {mobileNavigation} from '../../some address'
mobileNavigation()