Pattern for React when you optionally animate certain components - javascript

I have a few components that optionally animate based on certain state. For example, like mobile apps, if the sidebar is open and you tap a nav item in the sidebar we don't do the sliding animation between panels, but if its closed and you tap a link it slides the panels. "Panels" being pages. The code, right now, looks like:
render: function () {
var appContent;
if (this.state.sidebarOpen) {
appContent = <div className="app-content">
<this.props.activeRouteHandler ref="route" />
</div>
}
else {
appContent = <CSSTransitionGroup component={React.DOM.div}
className="app-content"
transitionName="pane-animate">
<this.props.activeRouteHandler ref="route" />
</CSSTransitionGroup>
}
return (
<div className="wrapper">
<Sidebar closeHandler={this.sidebarCloseHandler} ref="sidebar" />
<div className="inner-wrapper">
{appContent}
</div>
</div>
);
},
Having that if/else there for just changing if the section should animate or not seems gross and confusing to other developers when they come in and look at it. Is there a better pattern to this?

Will this work?
Uses JSX spreads from React v0.12.
var CSSTransitionIf = React.createClass({
render: function() {
if (this.props.test) {
return <CSSTransitionGroup {...this.props}>{this.props.children}</CSSTransitionGroup>
}
else {
var component = this.props.component
return <component className={this.props.className}>{this.props.children}</component>
}
}
})
//...
render: function () {
return <div className="wrapper">
<Sidebar closeHandler={this.sidebarCloseHandler} ref="sidebar" />
<div className="inner-wrapper">
<CSSTransitionIf test={!this.state.sidebarOpen} component={React.DOM.div}
className="app-content"
transitionName="pane-animate">
<this.props.activeRouteHandler ref="route" />
</CSSTransitionIf>
</div>
</div>
},
// ...

Related

how do you style Sap UI5's tabBar tabs?

This react component has sap-UI5 react-web-components being returned, my question
is how do I style the "Tabs" the tabBar. I have tried everything I can think of and I haven't changed a pixel in the tabs. Now I can easily style the tabBar?? But for some reason, the tabs are out of my reach. i have tried inline, style-components, stylesheets...
function LoadWebComp() {
const WebCompRef = useRef();
const supplyOption = () => {
return Object.keys(listOfStuff).map((stuff, i) => {
return <Tabs className="webCompToggleTab" key={Math.random()} additional-text={stuff} name={stuff} />;
});
}
return (
<div className="Page">
<div className="Tabs">
<TabBar ref={WebCompRef} className="webCompToggleTabBar" id="UI5TabContainer" tabs-overflow-mode="StartAndEnd" collapsed fixed>
{supplyOption()}
</TabBar>
<div className="wrapper"></div>
</div>
</div>
);
}
export default LoadWebComp;

Conditional rendering on React.js

render() {
const tableStyle = this.getTableStyle();
const tableSettings = this.getTableSettings();
return (
<div style={tables}>
<TablePosition
contextMenuOn={true}
step={this.props.step}
pdfData={this.props.pdfData}
tableSettings={tableSettings}
tableStyle={tableStyle}
fileName={this.state.fileName}
tableSize={this.getTableSize()}
tableOffset={this.state.tableOffset}
desiredWidth={700}
updateXOffset={x => this.updateXOffset(x)}
updateYOffset={y => this.updateYOffset(y)}
markTable={() => this.markTable()}
setOutputLabels={(row, col, val) => this.setOuputLabels(row, col, val)}
/>
</div>
);
if (!this.props.isThirdStep) {
return (
<div>
<div style={sideBySide}>
<PDFViewer
isThirdStep={this.props.isThirdStep}
paginationCallback={this.handlePageChange}
pdfData={this.state.pdfData}
desiredWidth={600}
selectedPage={this.props.savedPageNo}
/>
</div>
</div>
);
} else {
return (
<div>
<ReferenceMenu />
</div>
);
}
}
In my component's render, I try to render several components based on certain conditions.
So, basically, the TablePoisition always stays there, and the PDFViewer and ReferenceMenu renders conditionally.
However, what I see on both conditions is only the TablePosition component.
Is this not supposed to work?
As explained since you want to combine two components you should change your render logic. One component will be sit there always and the other one will be rendered conditionally. So, you need to render that last component with the sticky one in the same return. I would do something like this:
renderPDFViewer = () => (
<div>
<div style={sideBySide}>
<PDFViewer
isThirdStep={this.props.isThirdStep}
paginationCallback={this.handlePageChange}
pdfData={this.state.pdfData}
desiredWidth={600}
selectedPage={this.props.savedPageNo}
/>
</div>
</div>
);
render() {
const tableStyle = this.getTableStyle();
const tableSettings = this.getTableSettings();
return (
<div>
<div style={tables}>
<TablePosition
contextMenuOn={true}
step={this.props.step}
pdfData={this.props.pdfData}
tableSettings={tableSettings}
tableStyle={tableStyle}
fileName={this.state.fileName}
tableSize={this.getTableSize()}
tableOffset={this.state.tableOffset}
desiredWidth={700}
updateXOffset={x => this.updateXOffset(x)}
updateYOffset={y => this.updateYOffset(y)}
markTable={() => this.markTable()}
setOutputLabels={(row, col, val) => this.setOuputLabels(row, col, val)}
/>
</div>
{
!this.props.isThirdStep
? this.renderPDFViewer()
: ( <div><ReferenceMenu /></div> )
}
</div>
);
}
You need to place your conditional renders inside variables or something similar.
var conditionContent1 = null;
var conditionContent2 = null;
if(condition1){
conditionContent1 = <div>conditional content 1</div>;
}
if(condition2){
conditionContent2 = <div>conditional content 2</div>;
}
return (
<div id="wrapper">
<div>
content
</div>
{conditionContent1}
{conditionContent2}
</div>
);
I added a wrapper div; because, I believe render's return doesn't like having multiple root elements.
If the variables are null; then, it won't affect the overall render.

How to use the condition map function in ReactJS?

I am trying to display bootstrap carousel via ajax call using react js. Ajax receives json data consisting image name, content title and some meta information of per slide what I want to inject in DOM. So, I use the map function to generate all slides. My problem is, for the first slide I want to add a class active. But I do not know how to use condition in map().
In React, I have written: (in SliderWidget class, I have written a comment actually where I should use active class conditionally)
var HomeCarousel = React.createClass({
getInitialState: function() {
return {
data: []
}
},
componentDidMount: function() {
$.get("/api/slider", function(result) {
this.setState({
data: result
});
}.bind(this));
},
render: function() {
return (
<div id={"myCarousel"} className={"carousel slide"} data-ride="carousel">
{this.state.data.map((slider, i) => <SliderWidget key = {i} data = {slider} />)}
</div>
);
}
});
class SliderWidget extends React.Component {
render() {
return (
<div className={"item active"}> // here I want to use active class for the first slide
<img className={"first-slide"} src="images/pexels.jpeg" alt="First slide" />
<div className={"container"}>
<div className={"carousel-caption"}>
<h3>Research Indicates Breakfast is the Most Important Meal</h3>
<p><a className={"btn btn-primary"} href="#" role="button">Find Out More</a></p>
</div>
</div>
</div>
);
}
}
ReactDOM.render(
<HomeCarousel />, document.getElementById('react-home-carousel')
);
The i in the map callback is the loop index, so pass a property accordingly:
this.state.data.map( (slider, i) =>
<SliderWidget key={i} data={slider} active={i===0} />
)
Then in SliderWidget:
render() {
return (
<div className={"item" + this.props.active ? ' active' : ''}>...
)
}
Using classnames will make your life even easier.

Render JSX element based on condition

So I have a simple component within a web app I have been working on and I was wondering if there is a way I could render an element within this component based on the value of this.props.item.
here is my JSX:
var React = require("react"); var actions = require("../actions/SchoolActions");
module.exports = React.createClass({
deleteSchool: function(e){
e.preventDefault();
actions.deleteSchool(this.props.info);
},
render:function(){
return(
<div className="panel panel-default">
<div className="panel-heading">
{this.props.info.name}
<span className="pull-right text-uppercase delete-button" onClick={this.deleteSchool}>×</span>
</div>
<div className="panel-body">{this.props.info.tagline}</div>
</div>
)
} })
I wanted to be able to do something like this:
render:function(){
return(
code blah blah...
if (this.props.info = "nothing"){
<div className="panel-body">{this.props.info.tagline}</div>
}
...code blah blah
But I cannot write javascript withing the render function itself. Does anyone know how I could do this? Any help or advice is appreciated, thank you in advance.
You can use conditionally render using if and return the appropriate jsx
render(){
if(something){
return(<MyJsx1/>)
}else{
return(<MyJsx2/>)
}
}
You can chaage your component to:
render:function(){
return(
<div className="panel panel-default">
<div className="panel-heading">
{this.props.info.name}
<span className="pull-right text-uppercase delete-button" onClick={this.deleteSchool}>×</span>
</div>
{this.props.info = "nothing"?
(<div className="panel-body">{this.props.info.tagline}</div>)
:null}
</div>
)
} })
https://facebook.github.io/react/docs/conditional-rendering.html
Single line example
{(this.state.hello) ? <div>Hello</div> : <div>Goodbye</div>}
or
{(this.state.hello) ? <div>Hello</div> : false}
I often create an explicit function to to this, to avoid clutter in the main render:
var ChildComponent = React.createClass({
render: function () {
return (<p>I am the child component</p>)
}
});
var RootComponent = React.createClass({
renderChild: function () {
if (this.props.showChild === 'true') {
return (<ChildComponent />);
}
return null;
},
render: function () {
return(
<div>
{ this.renderChild() }
<p>Hello World!</p>
</div>
)
}
});
http://reactkungfu.com/2016/11/dynamic-jsx-tags/
For many React developers using JSX it is not clear how to make a
dynamic JSX tag. Meaning that instead of hardcoding whether it is
input or textarea or div or span (or anything else) we would like to
keep it in a variable.

React inline styles, applying styles from state

Using npm-inline-css module, I'm trying to change certain page elements colors, when storing the styles in a state. I set the state here:
setHeaderStyle: function(data){
var headerStyles = this.state.defaultStyles;
if(data) {
headerStyles.backgroundColor = data.first_colour;
headerStyles.color = data.theme;
}
this.setState({
branding: data,
headerStyles: headerStyles
});
},
Then I'm trying to apply the styles to the component:
render: function (){
return (
<div className="our-schools-app">
<InlineCss stylesheet="
& .button {
color: {{this.state.color}};
}
" />
<RouteHandler />
</div>
);
}
But they output like below. How can I set the inline styles? Or a better way I can do this?
<style scoped="" data-reactid=".0.0.1">#InlineCss-0 .button { color: {{this.state.color
}
}
;
}
</style>
From React Docs:
In React, inline styles are not specified as a string. Instead they are specified with an object whose key is the camelCased version of the style name, and whose value is the style's value, usually a string.
It looks like you're most likely trying to set styles for a button that exists in components that are rendered in RouteHandler.
If that's the case, it would make the most sense for you to create a wrapper that wraps the other components and accepts the styles you're trying to set.
For example:
var PageWrapper = React.createClass({
setHeaderStyle: function(data){
var headerStyles = this.state.defaultStyles;
if(data) {
headerStyles.backgroundColor = data.first_colour;
headerStyles.color = data.theme;
}
this.setState({
branding: data,
headerStyles: headerStyles
});
},
render: function () {
var buttonStyle = {
color: this.state.color
}
return (
<RouteHandler buttonStyle={buttonStyle} />
);
}
});
var Index = React.createClass({
render: function () {
return (
<div>
<RouteHandler />
</div>
);
}
});
var Signup = React.createClass({
render: function() {
return (
<div>
<p> Click below to signup now! </p>
<button style={this.props.buttonStyle}>Click Me!</button>
</div>
);
}
});
var Contact = React.createClass({
render: function() {
return (
<div>
<p> Click the button below to contact us </p>
<button style={this.props.buttonStyle}>Email Us!</button>
</div>
);
}
});
var routes = (
<Route path="/" handler={Index}>
<Route path="page" handler={PageWrapper}>
<Route path="signup" handler={Signup} />
<Route path="contact" handler={Contact} />
</Route>
</Route>
);
ReactRouter.run(routes, function (Handler) {
React.render(<Handler/>, document.body);
});
Edit: Per your request, as an example to show how nested routes would work, I added a Signup and Contact component. If you look at the routes variable you can see how I nested these components under PageWrapper.
Now the nested routes /#/page/signup and /#/page/contact will both get access to the props that are added to the <RouteHandler /> of PageWrapper. Hope this helps!!!!!

Categories

Resources