React component appears and disappears instantly in conditional rendering - javascript

For following scenario :
When user don't have admin access, else case is rendering and disappearing instantly after it.
I can see blank page only after it.
How to resolve this scenario ?
function Component () {
const isAdmin = checkIsAdmin('user')
return (
{ isAdmin ? (
return <div>Show admin page</div>
) : (
return <h1>You are not autherized</h1>
)
}
)
}

Related

Issues rendering the right dashboard UI user based on roles

I am trying to render UI in my project based on selected roles (brands, agency, influencer) on click. However, the logic that I am putting together is not loading the right UI and I don't quiet understand why not.
I have tried moving the role and setRole to the top component and passed the props down to the child components that read role and updated it via setRole so that I can have the state to be available in two places.
I also set a logic that should display components based on if the role equals the value of the buttons.
What happened was the components weren't loading upon clicking the function that handles click. However, logging out to the console if the role equals the value of the clicked button returns true, the right string that the logic was based on.
What I am expecting to happen is to load the component e.g: "Brands" when users click and select "brands" which is the value of the clicked button. Vise versa for the other components.
My code is as follows:
import { useState } from 'react';
import { useSession } from 'next-auth/react';
import Brands from './Brands';
import Agency from './Agency';
import CreatorsDash from './CreatorsDashboard';
export default function FirstPageModal({ role: userRole }) {
const [role, setRole] = useState(userRole);
const { data: session } = useSession();
const handleClick = (e) => {
e.preventDefault();
let buttonValue = e.target.value;
const clickedRole = role?.map((user) => {
let { role } = user;
if (buttonValue) {
userRole = { role: buttonValue };
}
return { userRole };
});
console.log(clickedRole); //Returns an array
clickedRole.map((item) => {
const { role } = item.userRole;
console.log(role); //Returns string ("agency" / "brands" / "Influencer")
if (session && role === 'brands') {
console.log(role); //This logs "brands" as expected but doesn't return the component
// return <Brands session={session} role={role} />;
} else if (session && role === 'agency') {
return <Agency session={session} role={role} />;
} else if (session && role === 'Influencer') {
return <CreatorsDash session={session} role={role} />;
} else {
console.log('Select a role');
}
});
};
return (
<>
<div className="">
<button type="button" className="" onClick={handleClick} value="agency">
As an Agency
</button>
<button type="button" className="" onClick={handleClick} value="brands">
As a Brand
</button>
<button
type="button"
className=""
onClick={handleClick}
value="Influencer"
>
As an Influencer
</button>
</div>
</>
);
}
Returning a component from an onClick handler doesn't automatically render the component. One thing you could do is to keep track of the role in the state and then put the <Brands /> <Agency/> and <CreatorsDash /> components in the render function and dynamically show/hide them like {role === "brands" && <Brands />. This can also be done with css, although the benefits of this are not so clear,.
Side note, it is very helpful to post a codepen with your code, especially as your code gets more complicated

ReactJS what is the proper way to wait for prop to load to avoid crashing my page?

all,
I am building a local website for myself for stocks. Currently I have a store that communicates with my tomcat instance to get stock market data, this works flawlessly.
on my frontend I am attempting to display my data but sometimes it works, sometimes it does not work and I get an "this child prop does not exist" so this is what I implemented:
try{
cellRend = this.cellRenderer;
columnLen = this.props.selectedStock.Revenue.length;
this.state.isLoading = false
}catch(error){
cellRend = this.cellRendererEmpty;
columnLen = 10;
}
if (this.state.isLoading === true){
return <div>Loading!</div>
}
where cellRenderer is my table, cellRendererEmpty is an empty table.
this kind of works and some times it will just display Loading! forever. so my question is what is the correct way to wait for a prop?
here is my full code:
const dispatchToProps = dispatch => {
return{
getSelStock: (stockId) => dispatch(stockActions.getSelStock(stockId))
};
}
class stockPage extends React.Component{
constructor(props) {
super(props);
this.state = {
columnLen:10,
data:null,
isLoading:true
}
console.log(this.props.isLoading)
this.cellRenderer = this.cellRenderer.bind(this);
this.render = this.render.bind(this);
}
cellRenderer({ columnIndex, key, rowIndex, style }) {
return (
<div className={"app"} key={key} style={style}>
<span></span>
{rowIndex === 0 ? (`${this.props.selectedStock.Revenue[columnIndex].date}`) : (
<span>{`${this.props.selectedStock.Revenue[columnIndex].value}`}</span>
)}
</div>
);
}
cellRendererEmpty({ columnIndex, key, rowIndex, style }) {
return (
<div className={"app"} key={key} style={style}>
{rowIndex === 0 ? (`${columnIndex}`) : (
<span>{`${columnIndex}`}</span>
)}
</div>
);
}
render() {
var cellRend, columnLen
console.log("Hey")
this.props.getSelStock(this.props.match.params.stockId);
try{
cellRend = this.cellRenderer;
columnLen = this.props.selectedStock.Revenue.length;
this.state.isLoading = false
}catch(error){
cellRend = this.cellRendererEmpty;
columnLen = 10;
}
if (this.state.isLoading === true){
return <div>Loading!</div>
}
return(
<div>
<h1>{this.props.match.params.stockId}</h1>
<AutoSizer disableHeight>
{({ width }) => (
<MultiGrid
cellRenderer={cellRend}
columnWidth={125}
columnCount={this.state.columnLen}
enableFixedColumnScroll ={1}
enableFixedRowScroll ={1}
fixedColumnCount
fixedRowCount
height={300}
rowHeight={70}
rowCount={2}
style={STYLE}
styleBottomLeftGrid={STYLE_BOTTOM_LEFT_GRID}
styleTopLeftGrid={STYLE_TOP_LEFT_GRID}
styleTopRightGrid={STYLE_TOP_RIGHT_GRID}
width={width}
hideTopRightGridScrollbar
hideBottomLeftGridScrollbar
hideBottomRightGridScrollbar
/>
)}
</AutoSizer>
</div>
)
}
}
export default connect(mapStateToProps, dispatchToProps)(stockPage);
From your title, I assume that when your page loads, you are fetching data then you use that data in the page. However, during initial load and when your fetching is still in process, your data is still null and your app will crash because the code is expecting data to have a value which it needs to use...
What you can do is while the data is fetching, then do not display the rest of the page yet (ie. you can just display a giant spinner gif), then once the fetching is complete then update isLoading state... Or you can set an initial value for the data so the page won't crash on load...
EDIT:
so using react lifecycle fixed your problem as per your comment... anyways just wanna add that you may want to use async/await instead of setTimeout like you did in your comment.. This is what the code might look like for async/await in lifecycles...
componentDidMount() {
const fetchData = async () {
await this.props.getSelStock() // your dispatch
// the state you want to update once the dispatch is done
this.setState({isLoading: false})
}
fetchData();
}

Send value to child component in react

I have a component that takes a parameter that can be true or false, I put it in the console to check.
console.log(isContract);
//can be true ou false
I need to send this value through a form that will render another component.
This is the parent component:
return (
<Contract
savingsFactors={formValues.savingsFactors}
onFieldSubmit={...}
/>
)
And here in the internal component, if my value that came from the other component is true, I need to change the items
const Contract = ({ savingsFactors }) => (
<PutField
label={label}
placeholder={placeholder}
onBlur={...}
// if isContract === true, return this:
items={savingsFactors === 'true' ? FORM_VALUES : FORM_VALUES_NORMAL}
// if isContract === false, return this:
items={savingsFactors === 'true' ? ANOTHER_FORM_VALUES : ANOTHER_FORM_VALUES_NORMAL}
/>
);
What is the simplest way to send the isContract to the internal component and load the items according to the result?
I'm studying react and I'm having a lot of trouble with it, thanks a lot to those who help
I'm more familiar with defined props in React, but If I remember correctly, this should go something like this:
Edit 1
Added a render method inside the Contract component.
Edit 2
I just realized that you have a component inside your contract component XD which should be inside the render method itself. I think that might be the issue.
return (
<Contract
savingsFactors={formValues.savingsFactors}
isContract={isContract}
onFieldSubmit={...}
/>
)
And your component should be something like (After Edit 2):
const Contract = (props) => (
render(){
let items = [];
if (props.isContract === true)
{
items={props.savingsFactors === 'true' ? FORM_VALUES : FORM_VALUES_NORMAL}
}
//BTW, should this be !== true? :P
if (props.isContract === true)
{
items={props.savingsFactors === 'true' ? ANOTHER_FORM_VALUES : ANOTHER_FORM_VALUES_NORMAL}
}
return (
<div>
<h2>I have {items.length} items... or something...<h2>
<PutField
label={label}
placeholder={placeholder}
**items={items}** /*Maybe?*/
onBlur={...}
/>
</div>
)
}
);

Nextjs Warning: Expected server HTML to contain a matching <div> in <div> when using conditional rendering

There are similar questions posed here and on Google, but none with answers that fit my scenario.
Basically, I want to display a different searchbar in the header, depending on what page I am on. This is nextjs.
But when reloading the page, I get the error in console:
Warning: Expected server HTML to contain a matching <div> in <div>
First thing I tried was
const currentPath = Router.router?.route;
return (
<div className="sub-bar">
{currentPath === '/products' && (
<Search />
)}
{currentPath === '/baseballcards' && (
<SearchBaseballCards />
)}
</div>
);
That generates the error when reloading the page, even if I comment either of them out.
Next thing I tried was the ternary route:
<div className="sub-bar">
{currentPath === '/baseballcards' ? <SearchBaseballCards /> : <Search />}
</div>
This actually worked but ternary is no good because I only want the search bar on the /products and /baseballcards pages.
Final thing I tried was:
const currentPath = Router.router?.route;
let searchbar;
if (currentPath === '/baseballcards') {
searchbar = <SearchBaseballCards />
}
else if (currentPath === '/products') {
searchbar = <Search />
}
else {
searchbar = null;
}
return (
<div className="sub-bar">
{searchbar}
</div>
);
This gives me the original error when reloading the page, so back to square one.
https://reactjs.org/docs/conditional-rendering.html
Rather than accessing the Router object directly with Router.router?.route, use the router instance returned by the useRouter hook. This will ensure that the rendering between server and client is consistent.
import { useRouter } from 'next/router';
const SearchBar = () => {
const router = useRouter();
const currentPath = router.asPath;
return (
<div className="sub-bar">
{currentPath === '/products' && (
<Search />
)}
{currentPath === '/baseballcards' && (
<SearchBaseballCards />
)}
</div>
);
};

Marketo form appearing twice in gatsby

I am having an issue while implementing marketo form with gatsby at times. I have created a custom component for marketo forms which works smoothly when an input form id is given.
I am using Drupal 8 as backend for gatsby front end, so all content for the site comes dynamically from drupal.
This is the code for custom component :
import React, { useEffect, useState } from 'react'
import { Link } from "gatsby"
const MarketoForm = ({ fid }) => {
let formId = `mktoForm_${fid}`
const [formSuccess, setFormSuccess] = useState(false)
let message = ''
switch (fid) {
case 1537: // get in touch form
message = <>
<h1>Thanks for the message!</h1>
</>
break;
default:
message = <>
<h1>Thanks for the message!</h1>
</>
break;
}
useEffect(() => {
const script = document.createElement('script');
document.body.appendChild(script);
// Depending on your lint, you may need this
// eslint-disable-next-line no-undef
MktoForms2.loadForm("//app-lon03.marketo.com", "416-MPU-256", fid, function (form) {
// Add an onSuccess handler
form.onSuccess(function (values, followUpUrl) {
// Get the form's jQuery element and hide it
form.getFormElem().hide();
// Return false to prevent the submission handler from taking the lead to the follow up url
setFormSuccess(true);
return false;
});
});
}, [])
return (
<>
{formSuccess ?
<div>
{message}
</div> : <form id={formId}></form>}
</>
)
}
export default MarketoForm
and if I call it like
<MarketoForm fid={146} />
It works perfectly without any issues.
I am trying to load html to a particular div, this html contains script as well.I have written code so that this code will be executed as well.
class article extends Component {
state = {
externalScript: ''
}
componentDidMount() {
let htmlContent = this.props.data && this.props.data.article &&
this.props.data.article.body.processed
if (htmlContent.length > 0) {
if(/<script>[\s\S]*<\/script>/g.exec(htmlContent)){
let extractedScript = /<script>[\s\S]*<\/script>/g.exec(htmlContent)[0];
this.setState({ externalScript: extractedScript })
}
}
}
componentDidUpdate(){
let scriptToRun = this.state.externalScript
if (scriptToRun !== undefined && scriptToRun !== '') {
let scriptLines = scriptToRun.split("\n")
scriptLines.pop()
scriptLines.shift()
let cleanScript = scriptLines.join("\n")
window.eval(cleanScript)
}
}
render(){
// fetches data here ....
<>
<MarketoForm fid={142} />
<MarketoForm fid={156} />
<div dangerouslySetInnerHTML={{ __html: article.body.processed }}>
</div>
</>
}
}
So in this article component other marketo form already exists which works fine. At times I can see the same form appearing more than once inside the div (content is from backend).
Upon inspecting the form i can see its just one form not two.
Have anyone faced this issue before? Please suggest some resolutions for this.
Thanks

Categories

Resources