react classNames using two conditional classes - reactjs

I have a div as following:
<div className={classNames("div-one",
{"half-width": this.state.showRegistration || this.state.showLogin})}>
</div>
What I want is: on !this.state.showRegistration || !this.state.showLogin this condition I want append "full-width" class to div-one instead of "half-width"
How can I achieve this?

!this.state.showRegistration || !this.state.showLogin
is not the negation of
this.state.showRegistration || this.state.showLogin
The proper negation would be !this.state.showRegistration && !this.state.showLogin.
But I guess you want something like this:
const registrationOrLogin = this.state.showRegistration || this.state.showLogin;
const classes = classNames("div-one", {
"half-width": registrationOrLogin,
"full-width": !registrationOrLogin
})
<div className={classes}}>
</div>
or
const classes = `div-one ${registrationOrLogin ? "half-width" : "full-width"}`;

const resultClass = {this.state.showRegistration || this.state.showLogin ? 'half-width' : 'full-width'};
<div className={classNames("div-one",
[resultClass]: true }>
</div>

Related

How to pass if condition loop output to a variable in reactjs

I need help to solve this
let someVar
render(
{
this.props.someData.map((items) =>
items.someotherData.map((item) =>
(item.data1 > 5 && item.data2 == "more") ? classNames({ "classname1": true })
: (item.data1 > 5 && item.data2 == "less") ? classNames({ "classname2": true })
: classNames({ "classname3": true })
))
}
<div className = { someVar } ></div>
)
I need my output of if loop to be pass to the variable
I tried many method. Nothing worked. Please give the solution
render() {
let someVar
this.props.someData.forEach(items =>
items.someotherData.forEach(item =>
item.data1 > 5 && item.data2 == 'more'
? someVar = 'classname1'
: item.data1 > 5 && item.data2 == 'less'
? someVar = 'classname2'
: someVar = 'classname3'
)
)
return <div className={someVar}></div>
}
I didn't really get what you were trying to do. Are you calling some function with the class names or something? Here is my best try to solve your problem though.
First we create the variable,
Then we do data processing. You shouldn't use map but instead the forEach if you are not returning anything. You are also overwriting the variable for each item (is this preferred behaviour?).
Then we actually return the React part of the code. Render function always needs to return JSX or null. Inside JSX we can use the someVar in the className. The final value of className needs to be a string. That's why we are putting strings to the someVar.

How to write the complicated rendering loop in React?

I am writing a nested loop in React. All I am seeing is the final return statements of tags. Where are the and going? Thank you.
{ this.state.data.headings.map( (heading, i) =>
<h3 key={i}>{heading}</h3> &&
// some headings do not have subheadings, tho
// they still have statements. deal with these cases first...
((this.state.data.subheadings[i].length === 0 &&
this.state.data.statements[i].map((statement, _j) =>
<p key={i+_j}>{statement}</p>)) ||
// cases where the group of statements has a subheading...
(this.state.data.subheadings[i].map((subheading, j) =>
<h4 key={i + j}>{subheading}</h4> &&
this.state.data.statements[i][j].map((statement, k) =>
<p key={i+j+k}>{statement}</p>))
)
)
)
}
A better way of doing this in my opinion is to separate this in different components each one of them taking care of one of the loops.in your case header,subheader,statement, etc.
There is everything ok with you code, except you can refactor it to make more readable.
Don't repeat yourself (DRY), always move duplicated code to separate component, in your example it is statement element. Also, i remove redundant key props.
render() {
const {headings, subheadings, statements} = this.state;
return headings.map((heading, i) =>
<div key={i}>
<h3>{heading}</h3>
{
subheadings[i].length
? subheadings[i].map((subheading, j) =>
<div key={j}>
<h4>{subheading}</h4>
<Statements statements={statements[i][j]}/>
</div>
)
: <Statements statements={statements[i]}/>
}
</div>
);
}
const Statements = ({statements}) => (
statements.map((statement, i) =>
<p key={i}>{statement}</p>
)
);
(omg folks,) feels like i had to take a picture to prove it...
solution, special thanks to a similar Q&A (I'm using React v15 out of an older template for Ether dApps)
{ headings.map( (heading, i) =>
[ <h3 key={i}>{heading}</h3>,
subheadings[i].length === 0 ?
statements[i][0].map( (statement, j) =>
<p key={j}>{statement}</p>,
) :
subheadings[i].map( (subheading, j) => (
[<h4 key={j}>{subheading}</h4>,
statements[i][j].map( (statement, k) =>
<p key={k} style={{color: 'green'}}>{statement}</p> )
]
))
])
}

Convert working VueJS component to ReactJS

I have a Vue component that works just fine. Now I'm trying to convert that code to ReactJS equivalent. My attempt on React
var ticksArray = Array.apply(null, {length: 27}).map(Number.call, Number);
export default class Timer extends Component {
constructor(props) {
super(props);
this.state = {
angle:250,
minangle:0,
maxangle:270,
xDirection:"",
yDirection:"",
oldX:0,
dragging: false
}
}
onMousedown(){
this.setState({dragging : true});
}
onMouseup(){
this.setState({dragging : false});
}
onMousemove(e){
if(!this.state.dragging)
return;
this.setState({
xDirection : this.state.oldX < e.pageX ? 'right' : 'left',
oldX:e.pageX,
yDirection: this.state.xDirection === 'left' ? 'down' : 'up'
});
if(this.state.yDirection === 'up' && this.state.angle + 2 <=
this.state.maxangle)
this.setState({angle:this.state.angle += 2})
else if(this.state.yDirection === 'down' && this.state.angle - 2 >=
this.state.minangle)
this.setState({angle:this.state.angle -= 2})
}
knobStyle(){
return {
'transform':'rotate('+this.state.angle+'deg)'
}
}
activeTicks(){
return (Math.round(this.state.angle / 10) + 1);
}
currentValue(){
return Math.round((this.state.angle/270)*100) + '%'
}
componentDidMount(){
document.addEventListener('mouseup',this.state.onMouseup)
document.addEventListener('mousemove',this.state.onMousemove)
}
render() {
var tickDivs = ticksArray.map(function(item) {
return (
<div key={item} className="tick"></div>
);
});
return (
<div id="timer">
<div className="knob-surround">
<div className="knob"></div>
<span className="min">Min</span>
<span className="max">Max</span>
<div className="ticks" className="n <= activeTicks ?
'activetick' : ''">
{tickDivs}
</div>
</div>
</div>
);
}
}
It's not working. I'm missing something. I'm assuming the problem lies in this code bit.
<div className="ticks" className="n <= activeTicks ?
'activetick' : ''">
Please help fix this.
Add this here instead of comment:
React uses the following syntax:
className={n <= activeTicks ? 'activetick' : ''}
In componentDidMount you assign handlers in a wrong way, should be like:
document.addEventListener('mouseup', this.onMouseup)
Note here that handler is not a part of your state. And the corresponding definition of the handler:
private onMouseup = () => {...}
The reason to store reference for the event handler instead of having class method - see in #3
Do not forget to unsubscribe your event handlers in componentWillUnmount like this:
window.removeEventListener("mouseup", this.onMouseup);
UPDATE:
Here is an example working without using arrow functions: https://jsfiddle.net/6dnrLw4n/4/

React className with ternary operator add class 'null'

I'm trying to conditionally apply a class to my component using an expression like this:
.map(function(list, index) {
<div className={"myClass " + (position === index ? 'active' : null)}>
}
But it keeps adding null as class, with an end result like this:
<div class="myClass active">...
<div class="myClass null">...
This is a simple example, with only 2 class names, so I could just replace null with the default class name. But in a more complex layout, I would need to duplicate the same name over and over again.
Is there a better approach to solve this problem?
You could use an empty string '' instead of null like:
.map(function(list, index) {
<div className={"myClass " + (position === index ? 'active' : '')}>
}
Also map should return a value:
.map(function(list, index) {
return <div className={"myClass " + (position === index ? 'active' : '')}>;
}
If you have multiple classes, you might consider building the list of classes from an array:
var classes = ["myClass"];
if (position === index) {
classes.push('active');
}
return (
<div className={classes.join(' ')}>
...
</div>
);
You can also consider using a helper function that will generate the className string from an object like this:
var classes = {
myClass: true,
active: position === index
};
classnames is one such utility (not the only one).
Remove the space from "myClass " to "myClass", then replace null with an empty string ""
.map(function(list, index) {
<div className={"myClass" + (position === index ? 'active' : "")}>
}
just use https://www.npmjs.com/package/classnames:
usage example:
<div className={cn({"active": position === index })} ></div>
Use && short-circuiting: className={"myClass " + (position === index && 'active')}
In this way, if position === index is false, because we are using &&, we short-circuit. JS skips over 'active' and we just move on with our lives.
React Solution:
className={`myClass ${index ? "active" : ""}`}
Different syntax
className={`myClass ${index && "active"}`}

ReactJS: create DOM on the fly

How to transform this:
{dataFormat: 'hello my [friend=https://en.wikipedia.org/wiki/Friendship]'}
to this:
<div>
hello my <a onClick={...} href="https://en.wikipedia.org/wiki/Friendship">friend</a>
</div>
I need to somehow be able to scan a string and create links on the fly. Any idea?
The dataFormat can contain more than one link with unknown order between "regular" text and links.
Ended up using regex which did the job.
JSBin: https://jsbin.com/yogepa/edit?js,output
Code:
renderSpan(content) {
return <span>
{content}
</span>
}
renderLink(content) {
const parts = content
.replace(/\[|\]/g, '')
.split('=');
return <a style={ styles.link } onClick={ alert }>
{parts[0]}
</a>
}
renderFormat() {
let { dataFormat } = this.state;
const regex = /(\[[^\]]+])*([^\[]+)(\[[^\]]+])*(\[[^\]]+])*([^\[]+)(\[[^\]]+])*(\[[^\]]+])*([^\[]+)(\[[^\]]+])*/;
const matches = regex.exec(dataFormat);
return matches.reduce((output, match, index) => {
if (match && index >= 2) {
output.push(match.indexOf('[') >= 0 ?
this.renderLink(match) :
this.renderSpan(match)
);
}
return output;
}, []);
}
I probably can improve the Regex expression though.

Resources