React not rendering component with inline styling on IOS - reactjs

I ran into a problem with my component not re-rendering after a state change, when using props driven inline styling, on IOS/iphone (not tested on ipad).
Here is the code sandbox: https://codesandbox.io/s/confident-meitner-2sju9?file=/src/FlexboxGap.jsx
Edit: adding the code here too as requested:
import { useState } from "react";
import "./FlexboxGap.styles.css";
function FlexboxGap({ visible, containerCat, propertiesCat }) {
const [gap, setGap] = useState(0);
const [rowGap, setRowGap] = useState(0);
const [columnGap, setColumnGap] = useState(0);
function onGapChange(event) {
setGap(event.target.value);
setRowGap(event.target.value);
setColumnGap(event.target.value);
}
function onRowChange(event) {
setRowGap(event.target.value);
}
function onColumnChange(event) {
setColumnGap(event.target.value);
}
return (
<div className="main-container">
<div>
{" "}
<div>gap: {gap}px</div>
<input
type="range"
className="slider-bar"
min={0}
max={20}
value={gap}
onChange={onGapChange}
/>
</div>
<div>
{" "}
<div>row-gap: {rowGap}px</div>
<input
type="range"
className="slider-bar"
min={0}
max={20}
value={rowGap}
onChange={onRowChange}
/>
</div>
<div>
{" "}
<div>column-gap: {columnGap}px</div>
<input
type="range"
className="slider-bar"
min={0}
max={20}
value={columnGap}
onChange={onColumnChange}
/>
</div>
<div
style={{
width: "100vw",
height: "250px",
backgroundColor: "grey",
display: "flex",
flexFlow: "row wrap",
justifyContent: "flex-start",
alignContent: "flex-start",
rowGap: `${rowGap}px`,
columnGap: `${columnGap}px`
}}
>
<div className="graph-item">item</div>
<div className="graph-item">item</div>
<div className="graph-item">item</div>
<div className="graph-item">item</div>
<div className="graph-item">item</div>
<div className="graph-item">item</div>
<div className="graph-item">item</div>
<div className="graph-item">item</div>
<div className="graph-item">item</div>
<div className="graph-item">item</div>
{/* This last invisible div is a hack to "force" react to re-render, by referencing the props rowGap and columnGap.
Otherwise, the rerender fails to happen on iphones. Working on Android
and desktop */}
<div className="hack-ghost">{`${rowGap}${columnGap}`}</div>
</div>
</div>
);
}
export default FlexboxGap;
While the state of rowGap and rowColumn is successfully changed, as well as the style, the div that depends on it does not get updated on iphones (fully updated).
Works on desktop and android devices.
I found a hack by adding a div that references the 2 states I need, and everything now "works".
The problem is:
1- it is hacky and
2-i am not sure i fully understand what is going on.
I thought of this hack by thinking that "i needed react to notice that the state changed inside this element".
Is it an issue with the way that inline css works // an ios implementation particularity?
Kind regards.

Related

react-bootstrap Carousel breaks when changing content during transition

video of issue:
When the carousel is transitioning from one slide to another, if another entry from a dataset is choosen, before the slide finishes its transition, the new images are rendered, but controls/timer are broken, so the carousel is not slidable any more (manually or automatically).
activeFish is a useState object with some fish data that gets changed with setActiveFish(newActiveFishDataObject) when a list item is clicked
Anyone have ideas for a solution?
<Carousel>
{activeFish['Image Gallery'].map((imageData, i) => (
<Carousel.Item key={imageData.title + i}>
<div className="image-container">
<img
className="d-block w-100"
src={imageData.src}
alt={imageData.alt}
/>
</div>
<Carousel.Caption>
<p>{imageData.title}</p>
</Carousel.Caption>
</Carousel.Item>
))}
</Carousel>
Replicate-
https://codesandbox.io/s/frosty-night-yckxro (thanks to #IgorGonak)
onload, immediately click the down arrow on the dropdown to expose options, mouse over option b, wait for transition to happen, click b rite in the middle of the transition. observe controls wont work for the 'b' dataset
I've created a dummy data with three entries and three images each entry. Then I built a select to select one and the carousel like yours - it is working on my side: When I choose another entry, the images in carousel are adjusted. The transition is working and is performed after each defined timeout:
https://codesandbox.io/s/frosty-night-yckxro
import React from "react";
import { Carousel, Form, Stack } from "react-bootstrap";
import data from "./fishData";
export default function App() {
const [activeFish, setActiveFish] = React.useState(data[0]);
const onSelect = (event) => {
const choosenFishName = event.target.value;
const choosenFish = data.find((fish) => fish.name === choosenFishName);
setActiveFish(choosenFish);
};
return (
<Stack className="m-3">
<Form.Group id="fish-select" className="mb-3" style={{ width: "18rem" }}>
<Form.Select value={activeFish.name} onChange={onSelect}>
{data.map((entry) => (
<option key={entry.name} value={entry.name}>
{entry.name}
</option>
))}
</Form.Select>
</Form.Group>
<p>Choosen fish is: {activeFish.name}</p>
<Carousel style={{ height: 200, width: 300 }}>
{activeFish["Image Gallery"].map((img) => {
return (
<Carousel.Item key={img.title}>
<img className="d-block w-100" src={img.src} alt={img.alt} />
<Carousel.Caption>{img.title}</Carousel.Caption>
</Carousel.Item>
);
})}
</Carousel>
</Stack>
);
}
Edit:
According to https://github.com/react-bootstrap/react-bootstrap/issues/6352 the problem here is that there is a state called "isSliding" in Carousel component. If it's true, the controls are deactivated. When we change children while sliding "isSliding" is true, but it's not set to false in the end, because the appropriate callback is never fired.
The solution is to reset the component by adding unique key to it:
<Carousel
key={activeFish.name}
interval={2000}
style={{ height: 200, width: 300 }}
>
{activeFish["Image Gallery"].map((img) => {
return (
<Carousel.Item key={img.title}>
<img className="d-block w-100" src={img.src} alt={img.alt} />
<Carousel.Caption>{img.title}</Carousel.Caption>
</Carousel.Item>
);
})}
</Carousel>

CSSTransition not working with stripe elements React

I have a CSSTransition that works until I add the CardElement from "#stripe/react-stripe-js";
<CSSTransition
classNames="method"
in={radio === 'add-card'}
exit={!(radio === 'add-card')}
timeout={500}
unmountOnExit>
<form id="payment-form" onSubmit={handleSubmit} className="stripe-ad">
<input
type="text"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter Email Address (Optional)"
/>
<CardElement id="card-element" options={cardStyle} onChange={handleChange} />
{error && (
<div className="card-error" role="alert">
{error}
</div>
)}
<p className={succeeded ? "result-message" : "result-message hidden"}>
Payment succeeded, see the result in your
<a
href={`https://dashboard.stripe.com/test/payments`}
>
{" "}
Stripe dashboard.
</a> Refresh the page to pay again.
</p>
</form>
</CSSTransition>
When I comment out the , the transition will work properly over the 500ms time interval. When I leave the Card element in, it will refuse to adhere to the transition rules.
I'm using the base cardstyle
const cardStyle = {
style: {
base: {
color: "#32325d",
fontFamily: 'Arial, sans-serif',
fontSmoothing: "antialiased",
fontSize: "16px",
"::placeholder": {
color: "#32325d"
}
},
invalid: {
color: "#fa755a",
iconColor: "#fa755a"
}
}
};
The problem is that the CardElement either has its own transition on mount, or the style needs to be changed. Has anyone ever had this issue with the stripe element on transition?
I suspect that this will not work as the Elements exist within a Stripe-hosted iframe. Only certain styles are supported on Elements:
https://stripe.com/docs/js/appendix/style
I suggest opening an issue on github with a minimal example of this, for example forked from the codesandbox demo.
https://github.com/stripe/react-stripe-js/issues

React local video does not load in production

I am trying to loop a very simple video contained in src/Assets/videos.
When I deploy a local server with npm start, the video performs as expected, however, when I publish to production the video does not load. I am using AWS Amplify CLI to publish the app.
I tried to:
1). View the app in a different browser (Firefox and Chrome).
2). Load the video from /public via an environment variable.
3). Load the video via the react-player module.
My initial code was home.js component rendered in app.js:
import heroVideo from '../../Assets/videos/heroVid.mp4';
//...
export default function HomePage() {
return (
<div id="hero" align="center" className="center">
<div>
<video muted autostart autoPlay loop >
<source src={heroVideo} type="video/mp4"/>
Your browser does not support the video tag.
</video>
</div>
<div style={{width: '90%'}}>
<div>
<img src={logo} style={{height: '200px', borderRadius: '100px'}} className={classes.blue} alt={`${props.brandName} Logo`}/>
<h4>A QC HOME BUYERS COMPANY</h4>
<h1>QC General Contractors</h1>
<h2 className="script">Let's build your future together</h2>
<NavLink to="/request-quote" className="simple-link"><Button variant="contained" color="secondary">Request a quote</Button></NavLink>
</div>
</div>
</div>
)
}
Then I tried to load from /public:
export default function HomePage() {
return (
<div id="hero" align="center" className="center">
<div>
<video src={process.env.PUBLIC_URL + 'Videos/heroVid.mp4} muted autostart autoPlay loop />
</div>
<div style={{width: '90%'}}>
<div>
<img src={logo} style={{height: '200px', borderRadius: '100px'}} className={classes.blue} alt={`${props.brandName} Logo`}/>
<h4>A QC HOME BUYERS COMPANY</h4>
<h1>QC General Contractors</h1>
<h2 className="script">Let's build your future together</h2>
<NavLink to="/request-quote" className="simple-link"><Button variant="contained" color="secondary">Request a quote</Button></NavLink>
</div>
</div>
</div>
)
}
Finally react-player:
import heroVideo from '../../Assets/videos/heroVid.mp4';
import ReactPlayer from 'react-player'
//...
export default function HomePage() {
return (
<div id="hero" align="center" className="center">
<div>
<ReactPlayer url={heroVideo} loop="true" volume="0" muted="true" playing="true" style={{height: "100%"}} />
</div>
<div style={{width: '90%'}}>
<div>
<img src={logo} style={{height: '200px', borderRadius: '100px'}} className={classes.blue} alt={`${props.brandName} Logo`}/>
<h4>A QC HOME BUYERS COMPANY</h4>
<h1>QC General Contractors</h1>
<h2 className="script">Let's build your future together</h2>
<NavLink to="/request-quote" className="simple-link"><Button variant="contained" color="secondary">Request a quote</Button></NavLink>
</div>
</div>
</div>
)
}
I am still relatively new to react and AWS Amplify - Is there something I am missing?
Thanks in advance for any guidance.
Have you modified your rewrite rules to add mp4 ?
</^[^.]+$|\.(?!(css|mp4|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>
I was having the same issue as well, the easiest solution I found was to create an S3 bucket on AWS and upload the video file there and grab the src from said video. You're also gonna have to add public read access for your bucket/object.
Did #jsc31994 recommendation :
Uploaded the video on a S3 bucket and then used ReactPlayer
<ReactPlayer
url='https://xxx.s3.us-east-2.amazonaws.com/xxx-background.mp4'
playing={true}
loop={true}
muted={true}
controls={false}
id="background_video"
/>

How do I change text on the button for npm package react-microsoft-login?

I'm trying to build a login/register page that will allow multiple users to login/register with multiple login providers such as Microsoft, Google, Instragram etc.
I managed to figure out how to do it with Google and Instagram 3rd party npm packages however, with the Microsoft Login button, there is no option to change the text at all? Is this possible? I want to change it from "Sign in with Microsoft" to "Log in with Microsoft" and "Register with Microsoft" I have my own functionality to handle oAuth registration process.
Here is my code I'll only show the portion that I cannot figure out. In addition, this is the link that shows what props are available for the package.
Microsoft Login npm package doc
import React from 'react';
import { useDispatch } from 'react-redux';
import MicrosoftLogin from 'react-microsoft-login';
import { Link, useHistory } from 'react-router-dom';
import * as actions from 'redux/actions';
const microsoftResponse = (err, response) => {
console.log('err = ', err);
console.log('response successful', response);
};
const RegisterPage = () => {
const dispatch = useDispatch();
const history = useHistory();
return (
<Page title={'Register'}>
<div className={'loginContainer shadow-lg bg-white rounded'}>
<div className={'loginWrapper'}>
<div className={'row'}>
<div className={'col-md-6'}>
<div className={'wrapperOverlay px-4'}>
<h1 className={'text-center'} style={{ borderBottom: '4px solid #ff0000', color: '#ff0000', padding: '20px 0' }}><strong>Register</strong></h1>
<div className={'providers text-center'}>
<ButtonRow id={'loginProvider'}>
<MicrosoftLogin
clientId={xxxxxxxxx}
authCallback={microsoftResponse}
redirectUri={xxxxxxxxx}
/>
</ButtonRow>
</div>
<div className={'separator py-3'}>Or create a new local account</div>
<div className={'formContainer'}>
<Form
enableReinitialize
form={'exampleFormName'}
onSubmit={(values) => alert(JSON.stringify(values, null, 2))}
>
<FieldInput name={'email'} label={'Email'} type={'email'} placeholder={'Email Address'} />
<FieldInput name={'password'} label={'Password'} type={'password'} placeholder={'Password'} />
<FieldInput name={'confirmpassword'} label={'Confirm Password'} type={'password'} placeholder={'Confirm Password'} />
<div className={'resendConfirmation pb-3'}>
<Link to={'/resendemailConfirmation'}>Resend email confirmation</Link>
</div>
<Button className={'w-100 text-center'} type={'submit'} variant={'primary'} text={'Register'} style={{ fontSize: '20px' }} />
<div className={'form-group text-right'}>
<div className={'registerButton pt-3'}>
<span>Already have an Account?</span>
<Link to={'/login'}>
<span id={'question'}>Log In</span>
</Link>
</div>
</div>
</Form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Page>
);
};
export default RegisterPage;
You can't change text "as it is", because for a button used SVG image. But as workaround, you can pass your custom button by a children prop, with any text that you want.
<MicrosoftLogin clientId={clientId} authCallback={loginHandler}>
<button>Log in with Microsoft</button>
</MicrosoftLogin>
Few things to keep in mind:
you need to do styling for custom button from scratch
button styles should be based on Official Microsoft brand design

Display correct components on change with selected value from dropdown?

I have a component called DropDown Single and that has an options param Object and Database. If the Object is selected then I want to show the Autocomplete component for the name Table. If Database is selected I want it to show the autocomplete named database. I have tried to cut down the code with only the components I need to be using. The onclick itself doesn't actually do anything yet but I am assuming I will need it when I want it to show the right component.
<div className='Main UnitTestsAutoCompleteWrapper' style={{display: 'flex', justifyContent: 'space-between'}}>
<div>
<DropdownSingle
options={['Object', 'Database']}
value='Object'
name='Search for unit tests'
onclick={onChange}
/>
</div>
<div style={{marginRIght: '10px'}} >
<AutoCompleteSingle
name='Table'
label='Table'
options={autoComplete.tablesAutoComplete}
onChange={autoComplete.onTableAutoCompleteFieldUpdate}
onSelect={onSelect}
uniqueIdentifier={0}
initialValue={targetObject}
/>
</div>
<div>
<AutoCompleteSingle
name='Database'
label='Database'
options={autoComplete.databasesAutoComplete}
onChange={(e) => onFieldUpdate(e, 'database')}
onSelect={onDatabaseSelect}
uniqueIdentifier={1}
triggerOnSelectOnBackspace
/>
</div>
</div>
Use this as a simple example to guide you, you should really read the documentation. This is all covered under Conditional Rendering:
import React, { useState } from "react";
export default function App() {
const [selectValue, setSelectValue] = useState("cow");
return (
<div>
<select onChange={(e) => setSelectValue(e.target.value)}>
<option value="cow">Cow</option>
<option value="sheep">Sheep</option>
</select>
{selectValue === "cow" ? <p>Cow</p> : <p>Sheep</p>}
</div>
);
}

Resources