Render a component in jsx if a certain condition is met - javascript

Really new to react, I have this part of navigation in my Navbar.js using react-router-dom useLocation hook, I am able to get the active path I have to views and I want to render custom text when a user arrives at the view with JSX something like
if(path==="login" || path==="signin"){
`<h1>welcome</h1> ${userName}!`
}
How can I check if condition A or B is met then render the appropriate text using jsx

You must explicitly tell what to return, in your example you do not return anything. So, You can do either :
if (path === "login" || path === "signin") {
return (
<>
<h1>welcome</h1> {userName}
</>
);
} else {
return null;
}
Or use operator && to conditionally render.
{
(path === "login" || path === "signin") && (
<>
<h1>welcome</h1> {username}
</>
);
}
Read more about conditional rendering [here]

You need to:
Return the value
Use JSX and not a string
Put everything in a container such as a React Fragment
Such:
if(path==="login" || path==="signin") {
return <>
<h1>Welcome</h1>
{userName}!
</>;
}
… but that logic should probably be handled by your routes rather than an if statement.

You can use the ternary operator for conditional rendering in JSX like
{path==="login" || path==="signin" ? <> <h1>welcome</h1> {userName} </> : null}
Simple :-)

Related

how to hide a button depending on the selected file

I'm making a blog where I need a button to appear only if a user selects a specific story, if the user selects other reports, the button should not appear.
These reports are in markdown file.
I thought of using a conditional rendering with a state and use
{
Show && (<div><div/>)
}
Here's the code where the commented part what was trying to do something
import markdownStyles from './markdown-styles.module.css'
import Show_button_1 from './show_button_1'
export default function PostBody({ content }) {
/*const retornarPagina=()=>{
if(content==_posts.receita_0.md){
return
<Show_button_1/>
}
*/
return (
<div className="max-w-2xl mx-auto">
<div
className={markdownStyles['markdown']}
dangerouslySetInnerHTML={{ __html: content }}
/>
<Show_button_1/>
</div>
)
}
I tried to do it this way but it didn't work (03/30/2022)
import React, {useState} from 'react'
import markdownStyles from './markdown-styles.module.css'
import Show_button_1 from './show_button_1'
export default function PostBody({ content }) {
const [Show, setShow] = useState(false);
const retornarPagina=()=>{
if(content===_posts.receita_0.md){
{setShow(true)}
}
}
return (
<div className="max-w-2xl mx-auto">
<div
className={markdownStyles['markdown']}
dangerouslySetInnerHTML={{ __html: content }}
/>
{Show && (<Show_button_1/>)}
</div>
)
}
I'm not sure I understood the question correctly, but one crutch I used to conditionally render components was
{
Show ? (<div><div/>) : (<></>) //doesn't render anything
}
This should work for you.
{content === '_posts.receita_0.md' && <Show_button_1/> }
If you need multiple lines:
{content === '_posts.receita_0.md' && (
<Show_button_1/>
)}
you won't be able to use conditional rendering on a full file, you may want to consider refactoring your code to send a title of the markdown file through props as well. so you would do something like so:
<MyComponent content={document.markdown} title={document.title}/>
Then you can easily do
{props.title === 'some_title' && <Show_button_1/> }

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>
);
};

How to use ternary condition to render jsx using react?

i want to return jsx if some condition is true if not undefined should be returned.
below is my code,
const showInfo = (item) {
return (
<div>
<div>
<span>name</span>
</div>
<div>
<button>click</button>
</div>
</div>
);
}
const Parent = () => {
return (
<Child
onDone = {({item}) => {
notify ({
actions: (condition === 'value1' || condition === 'value2' ) &&
showInfo(item) //should put this condition into showInfo method
})
}}
/>
);
}
what i am trying to do?
the above code works. but now i want to put the condition inside the showInfo method. so if condition is true return jsx and if condition is false should return undefined.
what i have tried?
I have tried something like below
const showInfo = (item) {
return
{(condition === 'value1' || condition === 'value2' ) ? <div>
<div>
<span>name</span>
</div>
<div>
<button>click</button>
</div>
</div>
: undefined
}
);
}
const Parent = () => {
return (
<Child
onDone = {({item}) => {
notify ({
actions: showInfo(item) //error here
})
}}
/>
);
}
but the above tried code, gives error "Type 'void' is not assignable to type 'ReactNode'" at actions statement.
could someone help me with this. i am not sure if i have used ternary operator properly. thanks.
EDIT
after trying one of the answers provided,
notify is a method that is returned from usehook
and it evaluates to the component below
const Something: React.FC<SomethingProps> = ({
description,
actions,
...props
}) =>
(
<Header>
<Title>{title}</Title>
</Header>
{(description ||actions) && (
<Body> //this is displayed
{description && <Description>{description}</Description>}
{actions && <Actions>{actions}</Actions>}
</Body>
)}
);
here the component is displayed when the condition fails in showInfo component.
in showInfo i am returning undefined if condition fails but still in the Something component the is displayed even though i have {description || actions}
i am not sure what is happening here.what is the condition i have to check for actions to not display in this case
i have tried
{(description ||actions !== 'false') && (
<Body> //this is displayed
{description && <Description>{description}</Description>}
{actions && <Actions>{actions}</Actions>}
</Body>
)}
and this works. i am wondering why i should specifically mention
actions !== 'false'
instead of actions only
could someone help me with this. thanks.
If you want to return jsx from function you should wrap them inside some component. In this case you cen use <React.Fragment> or just <>. Another problem which I can see is that you probably forgot about arrow in you arrow function. Also don't know from where variable names condition comes from.
const showInfo = (item) => {
return (
<>
{ condition === "value1" || condition === "value2" ? (
<div>
<div>
<span>name</span>
</div>
<div>
<button>click</button>
</div>
</div>
) : undefined}
</>
);
};
Wouldn't it be better to use the useState or useEffect hooks?

Render react component based on user permissions

I need to render a component based on the user role.
For example:
If the user is a sales persons he would see both buttons.
But if he is support he would see only the second button.
import React from 'react';
import Button from './MyCustomButton';
class App extends React.PureComponent {
render() {
return (
<Grid>
<Button> // visible only for sales manager
Action A
</Button>
<Button> // visible for support and sales manager
Action B
</Button>
</Grid>
)
}
}
I would really like to avoid if-else statements inside the render. Keep it clean as possible.
Is there a good design or some tools/decorator that could be useful here?
I've already handled it in the server side but I need a clean solution for the client side as well.
thanks.
You can inline ternary statements directly into your component tree, as shown below. If these boolean expression would evaluate to false, react will skip them automatically.
class App extends React.PureComponent {
render() {
const user = this.props.user;
return (
<Grid>
{user.isSalesManager && <Button>
Action A
</Button>}
{(user.isSalesManager || user.isSupport) && <Button>
Action B
</Button>}
</Grid>
)
}
}
In order to do that, you need to have the information about the user role in the props though.
Read more on conditional rendering in the React documentation.
One way you could do this is with an Authorizor component. It would be a very simple function that does your validation for you like normal, and just checks an authLevel. If you need to adjust this to work with your auth model thats fine.
function Authorizor(props) {
if (props.authLevel > props.user.authLevel) {
return null;
}
const { ComponentToValidate } = props;
return <ComponentToValidate {...props} />;
}
then usage would be something like
<Authorizor authLevel={1} ComponentToValidate={Button} {...this.props} />
in your example this would look like.
class App extends React.PureComponent {
render() {
return (
<Grid>
<Authorizor authLevel={2} ComponentToValidate={Button} label="Action A" onClick={this.handleActionAThingy} {...this.props} />
<Authorizor authLevel={1} ComponentToValidate={Button} label="Action B" onClick={this.handleActionBThingy} {...this.props} />
</Grid>
)
}
}
If it's just a matter of 'cleaner' look and not lack of condition (because you will have to have it somewhere) you could create simple reusable component:
const Visibility = ({ isVisible, children }) => (
isVisible ? React.Children.only(children) : null;
)
and use it like that
<Grid>
<Visibility isVisible={user.isSalesManager}>
<Button> // visible only for sales manager
Action A
</Button>
</Visibility>
<Visibility isVisible={user.isSalesManager || user.isSupport}>
<Button> // visible for support and sales manager
Action B
</Button>
</Visibility>
</Grid>
it's hard to come up with much better solution without knowing more about your application architecture, but if you keep your user roles in some kind of store accessible from anywhere (redux, context, whatever) you could create very similar component that accepts roles needed to see it's children (let's say an array of strings) and possibly some kind of descriptor (like all, oneOf etc. if your permissions system is more complicated) and component itself grabs needed data from global store and compares it to props it got. If that's your use case i can provide example.
Short code
render() {
const button1 = <Button>Action A</Button>; // visible only for sales manager
const button2 = <Button>Action B</Button>; // visible for support and sales manager
return (
<Grid>
{[user.type === 'salesManager' ? button1 : null, button2]}
</Grid>
)
}
I generally use like following in these kind of scenarios
render(){
var buttonADiv = <Button> // visible only for sales manager
Action A
</Button> ;
var buttonBDiv = <Button> // visible for support and sales manager
Action B
</Button> ;
var rows = [];
if(user === 'sales'){
rows.push(buttonADiv);
rows.push(buttonBDiv);
}
else if(user === 'support'){
rows.push(buttonBDiv);
}
return (
<Grid>
{rows}
</Grid>
)
}
import React from 'react';
import Button from './MyCustomButton';
class App extends React.PureComponent {
render() {
if(user.type = 1){
return (
);
}
else if(user.type = 2){
return (
);
}
}
}

Categories

Resources