Need a little guidance with conditional rendering in react
class Car extends React.Component {
id = '123456'
render() {
if("id".includes("1") === true){
return <h2>$$${id}</h2>;
}
else{
return <h2>{id}</h2>;
}
}
For rendering $$$ for certain condition , apart from using if else and rendering
is there any way to conditionally render ???
a better way and the return can be quite long in big applications
is there a way to write conditional and return the value according to it?
Your question is not very clear so do well to add some clarity if my answer is not satisfactory.
When you want to conditionally render in react you can use the short-circuiting property of the && operator.
For example:
(false && "Logged In")
//Logged In
So using this idea, you can do the same for components
function App(props) {
let element
if(props.loggedIn) {
element = <div>Logged In</div>
} else {
element = <div>Not Logged In</div>
}
return element
}
simply becomes
function App(props) {
return (
<div>
{
props.loggedIn &&
<h3>You're logged in as {props.data.username}</h3>
}
</div>
)
}
There's a variety of ways to do conditional rendering. Here is one example with a ternary operator for simple cases:
render() {
return <h2>{id.includes("1") ? "$$$" : ""}{id}</h2>
}
You can also look into using a switch statement, where you move the conditional logic outside of the render function.
Related
I want to apply different style for selected element from a long list.
I'm passing to React component element as props: currentId and selectedId.
Inside render function, I compare both ids and apply proper styles.
When clicking any element from the list, I fire an action with the new selected Id and all elements in the list will re-render(because selectedId prop does change).
If the list has 1000 element and I click one of them, It would be nice to only update 2 elements (new selected and deselected ones) not all of them.
Is these a better way to handle this scenario in React?
Update: Add code example
List component:
const MyList = (props) => {
const items = props.items;
const selectedId = props.selectedId;
return (
<div>
{items.map((item) => (
<MyItem
currentId={item.id}
selectedId={selectedId}
key={item.id}
content={props.content}
/>
))}
</div>
);
};
Item component:
const MyItem = (props) => {
const isSelected = props.currentId === props.selectedId;
return (
<div className={isSelected ? 'selected-item' : ''}>
<h1>{props.currentId}</h1>
</div>
);
};
You can implement shouldComponentUpdate logic to prevent components from rerendering. Generally this is a bad idea (more on that later) but it does seem to apply to your use case. In general it is better to simply use PureComponent to prevent unneeded rerenders. This implements shouldComponentUpdate logic that compares state and props and if neither has changed, no update occurs.
Without seeing your code this is my best guess as to what shouldComponentUpdate might look like in your context:
shouldComponentUpdate(nextProps) {
if(this.state.isSelected && this.state.id !== nextProps.selectedId) {
return true;
} else if (!this.state.isSelected && this.state.id === nextProps.selectedId) {
return true;
}
return false;
}
Note that this means that a rerender will not happen unless shouldComponentUpdate returns true or you call this.forceUpdate() on that component. Your component won't even render if this.setState() is called, unless you add in more specific logic so that shouldComponentUpdate returns true on state changes. This can lead to difficult to debug problems, where your UI fails to reflect changes in application state but no obvious error occurs. This behavior doesn't apply to child components, so if these components have children they will still rerender as expected. If you decide to implement shouldComponentUpdate, you can add logic to compare state as well by declaring the nextState parameter:
shouldComponentUpdate(nextProps, nextState) {
if(this.state.isSelected && this.state.id !== nextProps.selectedId) {
return true;
} else if (!this.state.isSelected && this.state.id === nextProps.selectedId) {
return true;
} else if (/*compare this.state to nextState */) { .... }
return false;
}
Implementing your own shouldComponentUpdate is tricky, and may require you to restructure your code for best results (for example, passing an isSelected variable to your components instead of allowing those components to decide whether or not they are selected might allow you to easily implement PureComponent). Best of luck!
I need to use componentWillReceiveProps() to call a method in my component once three conditions are met. Two of these conditions compare current props to next props, and those two receive their values via an Ajax request. The problem is not all conditions will be true at the same time.
For example.
export class Styles extends Component {
componentWillReceiveProps(nextProps) {
if (
!_.isEmpty(nextProps.one) && // set via ajax request
!isEqual(this.props.two, nextProps.two) &&
!isEqual(this.props.three, nextProps.three) // set via ajax request
) {
this.myMethod();
}
}
myMethod() {
… do something
}
render() {
return (
<div />
)
}
}
Because two of the props are being set with an Ajax response, I can’t be sure when those values are set and when they’ll fulfill the condition. I obviously need to achieve three true values in order to call this.myMethod(), but instead I get various combinations of true/false at any given time. It’s a bit of a lottery scenario.
Do I ultimately need to manage each of these conditions temporarily in state, then clear them out when they’re met?
You could do this without the deprecated componentWillReceiveProps with something like this:
export class Styles extends Component {
isDirtyTwo = false;
isDirtyThree = false;
..
componentDidUpdate(prevProps) {
this.isDirtyTwo = this.isDirtyTwo || !isEqual(prevProps.two, this.props.two);
this.isDirtyThree = this.isDirtyThree || !isEqual(prevProps.three, this.props.three);
if (!_.isEmpty(this.props.one) && this.isDirtyTwo && this.isDirtyThree) {
this.isDirtyTwo = false;
this.isDirtyThree = false;
this.myMethod();
}
}
..
}
This will call myMethod when one is empty and both other props have changed at some point. (I'm assuming that once one is empty it stays that way, but if not, you could add another property for it.)
I wanted to update this variable when the condition is true, but it doesn't let me, thanks
constructor(props){
super(props);
var isActive = false;
this.props.items.map(item => (
if(item.name == this.props.product.name) {
isActive = true;
}
));
this.state = {
active: isActive
};
console.log(isActive);
this.handleClick = this.handleClick.bind(this);
}
Reason is, you forgot to use {}, If you are using any condition or wants to do some calculation use {} and put all the statement inside that. One more thing since you just want to iterate the array means not returning anything, so i that case use forEach instead of map, Use this:
this.props.items.forEach(item => { //here
if(item.name == this.props.product.name) {
isActive = true;
}
});
Check this code it will produce the same error:
[1,2,3,4].forEach(el=>(
if(el % 2 == 0)
console.log(el);
))
Check the working example:
[1,2,3,4].forEach(el=>{
if(el % 2 == 0)
console.log(el);
})
You really aren't passing an 'active' property nor state. You are trying to set a computed property, much like Ember (see How to setup Ember like computed properties in Immutablejs and Redux and Flux and React). This was considered for React and dismissed.
You should just create a function, isActive() and call it when needed. I expect you only need it when rendering a set of individual item components for which isActive is a property.
That said, there are ways of cramming this into a React codebase, but your code will be unmaintainable.
In my state I have showTab1, showTab2, showTab3. If tab i is selected, then the other tabs are set to false. So in my render function I want to be able to return something like this:
return (
<div>
{
(() => {
if (someCondition) {
if (this.state.showTab1) {
return (
<div>
<Tab1/>
</div>
)
} else if (this.state.showTab2) {
return (
<div>
<Tab2/>
</div>
)
} else if (this.state.showTab3) {
return (
<div>
<Tab3/>
</div>
)
}
}
return <span />;
})()
}
<AnotherComponent>
</div>
);
But I know that it's not allowed to have multiple returns, or at least it's considered bad practice. How can I get around this?
Ideally you'd use a single variable to determine which tab you need and then you could use a switch statement instead of multiple ifs. Something like this would be nice:
render() {
const { currentTabId } = this.props;
let CurrentTab;
switch( currentTabId ) {
case 'tab1':
CurrentTab = Tab1;
break;
case 'tab2':
CurrentTab = Tab2;
break;
case 'tab3':
CurrentTab = Tab3;
break;
default:
CurrentTab = null;
};
return <div>{ CurrentTab && <CurrentTab /> }</div>;
}
or
render() {
const { currentTabId } = this.props;
const tabs = {
tab1: Tab1,
tab2: Tab2,
tab3: Tab3,
};
const CurrentTab = tabs[ currentTabId ] || null;
return <div>{ CurrentTab && <CurrentTab /> }</div>;
}
What do your tabs have in common, and what makes one different from the other ones?
Having that in mind create a single Tab component that takes the needed properties (differences) and renders accordingly. But ... why?
React is awesome because it can know the minimal amount of changes needed to the DOM in order to represent the state you've set, allowing you to handle your entire UI as a state-based system. The good performance of React is based on how well it can tell those differences.
If your render method returns an entirely different component each time, React will remove one and append the other because it can't tell the difference between one and the other. But if you specify with properties and the state what changes and what doesn't change in your component, then it'll do its job very well. The DOM is awful, it has always been, the less changes you make to it, the better your page will behave.
Does that mean you can't return three entirely different components? Of course not, but if you would do that on all of your components, then you would have a very serious performance issue. That sounds pretty much like a bad practice and good enough reason to avoid it.
Take SO tabs at the right as a very trivial example, and supose you navigate to them from other place in the page, therefore only the one active is shown.
If you do this:
<div>
{() => {
if (this.state.active === 'jobs')
return <Jobs>;
if (this.state.active === 'doc')
return <Documentation>;
// ... you get it
}}
</div>
Whenever you change state.active React will remove the tab, and append a new one.
But if you don't use a bad practice, and use a good practice like stateless functional components
const Tab = ({text, href, children}) => (
<div>
<a href={href}>{text}</a>
{children}
</div>
);
// In the parent one
textByTab() {
switch(this.state.active) {
case 'jobs':
return 'Jobs';
case 'doc':
return 'Documentation';
}
}
hrefByTab() { // ... you get it }
childrenByTab() {
if (this.state.active === 'doc')
return <span className="beta-thing">Beta</span>;
}
render() {
return (
<div>
<Tab text={this.textByTab()} href={this.hrefByTab()}>
{this.childrenByTab()}
</Tab>
</div>
);
}
Now React knows exactly what can change, how it can change, and can even do fancy functional stuff for even better performance.
I'm wondering how to dynamically request a component based on a variable value. What I'm trying to accomplish here is the following:
import Template1 from './Template1.jsx';
import Template2 from './Template2.jsx';
var ComponentTemplate = (some_condition === true) ? "Template1" : "Template2"
render() {
<ComponentTemplate prop1="prop1 val" />
}
Is this even possible? If so, how?
It is not clear to me why you need to use a string representation of a class rather than just switch the component or use a conditional render:
var Component = some_condition === true ? Template1 : Template2;
// ...
return ( <Component /> );
But assuming this is an oversimplification, the easiest thing to do would be to use a mapping object that translates a string into a component. With ES2015 enhanced object literals, it becomes fairly straightforward:
var Components = {
Template1,
Template2,
};
var Component = condition ? Components['Template1'] : Components['Template2'];
// ...
return ( <Component /> );
If you are just looking to render different component based on the condition you could actually have 2 other render function and inside render() you could check the condition and call corresponding render
render () {
!this.state.isAuthorized? renderLogin(): renderTweets();
}
renderLogin () {
<LoginView/>
}
renderTweet () {
<ListTweets/>
}
Hope this is what you were looking for!
All the dynamic rendering should inside Render function. Because the JSX compile will depend on the Variable name not the Object reference.
If you write <Component />,
it will transfer to React.createElement('Component').
Cannot refer to the dynamic component you want to choose.
depend on the condition when Render is running. Use different React tag you want.
render() {
condition ? <Template1 /> : <Template2 />
}