Rendering old ReactJS components with new ReactJS - javascript

I'm currently porting a very old ReactJS application to ReactJS 16 however I'm struggling on how the render function works since I don't have a React.DOM anymore.
On the old component I've got the following (I've removed unnecessary code from example):
define([
'react'
], function(
React
){
var D = React.DOM;
return React.createClass({
render: function() {
//If the Engine is not connected or the game is starting
if(this.state.engine.connectionState !== 'JOINED' || this.state.engine.gameState === 'STARTING')
return D.div({ className: 'bet-bar-starting' });
var betPercentages = calculatePlayingPercentages(this.state.engine);
var playingLostClass, cashedWonClass, mePlayingClass;
if(this.state.engine.gameState === 'ENDED') {
playingLostClass = 'bet-bar-lost';
cashedWonClass = 'bet-bar-won';
mePlayingClass = StateLib.currentlyPlaying(this.state.engine)? 'bet-bar-me-lost': 'bet-bar-me-won';
} else {
playingLostClass = 'bet-bar-playing';
cashedWonClass = 'bet-bar-cashed';
mePlayingClass = StateLib.currentlyPlaying(this.state.engine)? 'bet-bar-me-playing': 'bet-bar-me-cashed';
}
return D.div({ className: 'bet-bar-container' },
D.div({ className: cashedWonClass, style: { width: betPercentages.cashedWon + '%' } }),
D.div({ className: mePlayingClass, style: { width: betPercentages.me + '%' } }),
D.div({ className: cashedWonClass, style: { width: betPercentages.cashedWonAfter + '%' } }),
D.div({ className: playingLostClass, style: { width: betPercentages.playingLost + '%' } })
);
}
});
});
However I'm struggling to understand how to rewrite the render() function to the latest ReactJS version? I've managed to do the following, but I don't understand how to do the multidimensional calls to the DOM.
class BetBar extends React.Component {
render() {
if(this.state.engine.connectionState !== 'JOINED' || this.state.engine.gameState === 'STARTING')
return (<div class='bet-bar-starting'/>);
let betPercentages = calculatePlayingPercentages(this.state.engine);
let playingLostClass, cashedWonClass, mePlayingClass;
if(this.state.engine.gameState === 'ENDED') {
playingLostClass = 'bet-bar-lost';
cashedWonClass = 'bet-bar-won';
mePlayingClass = StateLib.currentlyPlaying(this.state.engine)? 'bet-bar-me-lost': 'bet-bar-me-won';
} else {
playingLostClass = 'bet-bar-playing';
cashedWonClass = 'bet-bar-cashed';
mePlayingClass = StateLib.currentlyPlaying(this.state.engine)? 'bet-bar-me-playing': 'bet-bar-me-cashed';
}
//I don't understand how to do the D.div functions...
}
}
ReactDOM.render(<BetBar />);

The code you are looking at is from before JSX. JSX introduced a syntax which allows you to create elements without calling functions. This results in a much more declarative style, similar to HTML, which allow you to describe your components.
To translate old code -- pre JSX -- to modern day React, all you need to do is understand the function call.
D.div({ className: 'bet-bar-container' })
This creates a div with the className "bet-bar-container", in React is takes the HTML attributes as arguments and applies them to the desired DOM element for you.
<div className="bet-bar-container"></div>
So, for example with the code you have, it would roughly translate to something like this:
<div className="bet-bar-container">
<div className="cashedWonClass", style={{ width: betPercentages.cashedWon + '%' }}></div>
<div className="mePlayingClass", style={{ width: betPercentages.me + '%' }}></div>
<div className="cashedWonClass", style={{ width: betPercentages.cashedWonAfter + '%' }}></div>
<div className="playingLostClass", style={{ width: betPercentages.playingLost + '%' }}></div>
</div>

Related

TypeStyle how to pass mixins to nested elements

I want to include a mixin within a nested element in TypeStyle.
The mixin is working great, on the main / root element, but not on a nested element.
export const fontSize = (value: number) => {
const valueStr = value + 'px';
return {
fontSize: valueStr
}
};
export const warning = style(
fontSize(15), {
$nest: {
'& span': ( fontSize(12), {
backgroundColor: 'yellow'
})
}
});
<div className={warning}>
This text is formatted correctly
<span>this text is not</span>
</div>
I'm not sure if it's even possible to pass mixins to a nested element. I can give the span element an extra class, but that would be more code.
If the element is nested, you obviously want to go for the nested selector >, the & selector could for instance be used for :hover:
// fontSize function given by author
const fontSize = (value: number) => {
const valueStr = value + 'px';
return {
fontSize: valueStr
}
};
// cleaner definition of fontSize function
const fontSizeFunc = (value: number) => ({ fontSize: `${value} px` });
// correct styling object using fontSize function
export const warning = {
...fontSize(15),
$nest: {
">": {
span: {
backgroundColor: "yellow",
...fontSize(12),
},
},
},
});
// correct styling object not using fontSize function
export const warning = {
fontSize: 15,
$nest: {
">": {
span: {
backgroundColor: "yellow",
fontSize: 12,
},
},
},
});
EDIT: Added usage of fontSize function which returns an object, thus requiring the spread operator to yield a correct JS object.

Component inside Component - VueJS

I am having a hard time to understand this, so I have a component which is already complied which is a grid, now when I click on a button a modal pops-up and display another grid inside the modal at this point my code looks like this for the modal pop-up
<template>
<transition v-if="this.modalVisible" v-bind:title.sync="this.modalVisible" name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
{{ modalHeaderName }}
</div>
<div class="modal-body">
//this is another component
<grid-data :grid-values="dummy" :tool-bar="false"></grid-data>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
import DataTable from './core/gridTable.vue';
export default {
components:{
JqxButton,
'grid-data' : DataTable,
},
props : {
modalHeaderName : String,
modalVisible : Boolean
},
data: function () {
return {
buttonWidth: 120,
buttonHeight: '100%',
value: this.buttonName,
dummy : [
{ name: 'ProductName', type: 'string' },
{ name: 'QuantityPerUnit', type: 'int' },
{ name: 'UnitPrice', type: 'float' },
{ name: 'UnitsInStock', type: 'float' },
{ name: 'Discontinued', type: 'bool' }
],
}
}
}
</script>
Now, the grid is a vue component which was already complied and rendered, now will I import it again it says
[Vue warn]: Failed to mount component: template or render function not defined.
<template>
<div>
<!-- sync here is, getting the value from the updated modal-->
<custom-modal :modal-visible="this.showModal" v-bind:showModal.sync="showModal" :modal-header-name="this.modalHeaderName"></custom-modal>
<JqxGrid :width="width" :source="dataAdapter" :columns="gridValues"
:pageable="true" :autoheight="true" :sortable="true"
:altrows="true" :enabletooltip="true" :editable="true"
:selectionmode="'multiplecellsadvanced'" :showtoolbar="this.toolBar" :rendertoolbar="rendertoolbar">
</JqxGrid>
</div>
</template>
<script>
import JqxGrid from "../jqx-vue/vue_jqxgrid.vue";
import CustomModal from "../customModal";
export default {
components: {
JqxGrid,
'custom-modal' : CustomModal
},
// added the name here
name: 'jqx-grid',
props : {
gridValues : Array,
toolBar : Boolean
},
data: function () {
return {
showModal : false,
modalHeaderName : '',
width: '100%',
dataAdapter: new jqx.dataAdapter({
datatype: 'xml',
datafields : this.gridValues,
url: ''
}),
columns: []
}
},
mounted: function () {
this.createButtons();
},
methods: {
rendertoolbar: function (toolbar) {
let buttonsContainer = document.createElement('div');
buttonsContainer.style.cssText = 'overflow: hidden; position: relative; margin: 5px;';
let addButtonContainer = document.createElement('div');
let deleteButtonContainer = document.createElement('div');
addButtonContainer.id = 'addButton';
deleteButtonContainer.id = 'deleteButton';
addButtonContainer.style.cssText = 'float: left; margin-left: 5px;padding-bottom:25px;';
deleteButtonContainer.style.cssText = 'float: left; margin-left: 5px;padding-bottom:25px;';
buttonsContainer.appendChild(addButtonContainer);
buttonsContainer.appendChild(deleteButtonContainer);
toolbar[0].appendChild(buttonsContainer);
},
createButtons: function () {
let addButtonOptions = {
height: 25, value: ' <i class="fa fa-plus" style="padding-top:3px"></i> Add Items ',
};
let addButton = jqwidgets.createInstance('#addButton', 'jqxButton', addButtonOptions);
let deleteButtonOptions = {
height: 25, value: ' <i class="fa fa-ban" style="padding-top:3px"></i> Remove All ',
};
let deleteButton = jqwidgets.createInstance('#deleteButton', 'jqxButton', deleteButtonOptions);
// add new row.
addButton.addEventHandler('click', (event) => {
this.showModal = true;
this.modalHeaderName = 'Bulk Add Items';
});
// delete selected row.
deleteButton.addEventHandler('click', (event) => {
// alert('delete')
});
},
cellsrenderer: function (row, columnsfield, value, defaulthtml, columnproperties, rowdata) {
if (value < 20) {
return '<span style="margin: 4px; float: ' + columnproperties.cellsalign + '; color: #ff0000;">' + value + '</span>';
}
else {
return '<span style="margin: 4px; float: ' + columnproperties.cellsalign + '; color: #008000;">' + value + '</span>';
}
}
}
}
</script>
How can I overcome this issue?
I have seen question like this which says the component grid is trying to compile again and hence the error but I am not sure of that, so we should be using the complied version of the grid component.
NOTE: Using Vue with Laravel 5.4
Error Image
I didn't see an obvious error when you first posted the code. Right now I see JqxButton inside components of the upper code block, which would be undefined. In your code, you always import some components for which we can't see the code.
Generally, when I'm in a situation like this and everything seems to be looking okay, I remove all sub-components and see if the error goes away. Then, I re-add one component after each other until I hit the error again and try to debug it there.
From your description, I suspect you have some kind of cycle in your dependencies and you might find the documentation about circular references helpful.
Vue needs a lazy import for circular dependencies:
components: {
"my-circular-dependency": () => import("./my-circular-dependency.vue");
}

Using ReactJS createElement to output HTML without JSX

I am trying to create this code in ReactJS without JSX
<li>
<a href="javascript:;" onClick={onClick ? this.handleClick : null}>
<div className="home-gallery" style={{background: `url(${photo})`}}/>
</a>
</li>
Reason is due to altering previous code in a component that doesn't quite fit my needs. Reading some other posts I came to this but its far from working.
_createClass(Photo, [{
key: 'handleClick',
value: function handleClick(event) {
var _props = this.props,
onClick = _props.onClick,
index = _props.index,
photo = _props.photo;
onClick(event, { photo: photo, index: index });
}
}, {
key: 'render',
value: function render() {
var _props2 = this.props,
photo = _props2.photo,
onClick = _props2.onClick,
margin = _props2.margin;
var imgStyle = { background: `url(${photo})`, margin: margin };
return
_react2.default.createElement('li', null,
_react2.default.createElement('a', _extends({
onClick: onClick ? this.handleClick : null
},
_react2.default.createElement('div', _extends({
style: onClick ? _extends({}, imgStyle, imgWithClick) : imgStyle
}))
))
)
}}]);
Could someone point me in the direction of fixing this or reference how to best learn what I am doing wrong.
UPDATE
I have no figured out the majority of my query with altering to but the background: 'url(${photo})' is still not producing, whilst the margin is.
var imgStyle = { background: `url(${photo})`, margin: margin };
return _react2.default.createElement(
"li",
null,
_react2.default.createElement(
"a",
{ href: "javascript:;", onClick: onClick ? this.handleClick : null },
_react2.default.createElement("div", { className: "home-gallery", style: onClick ? _extends({}, imgStyle) : imgStyle })
)
);
Okay, I came to the solution by using the online Babel compiler. Putting in the JSX gave an output that lead me toward the solution.
var imgStyle = { backgroundImage: 'url(' + photo.src + ')', margin: margin };
console.log(photo)
return _react2.default.createElement(
"li",
null,
_react2.default.createElement(
"a",
{ href: "javascript:;", onClick: onClick ? this.handleClick : null },
_react2.default.createElement("div", { className: "home-gallery", style: onClick ? _extends({}, imgStyle) : imgStyle })
)
);

Rendering grid in React using lodash

I struggle to render a simple grid for my test project.
Didn't want to create grid by hand, because with bigger grids that would not only be a chore, but also the code would be cluttered, so figured I should use lodash for this.
However, I can't seem to render the grid, it's just not visible even when I inspect in dev tools. Can someone point my mistakes?
I am also fine with using other tools than lodash if necessary.
Here is the code:
import React from 'react';
import _ from 'lodash';
import './game.css';
const GRID = [
[{x: 1, y:3}, {x:2, y:3}, {x:3,y:3}],
[{x: 1, y:2}, {x:2, y:2}, {x:3,y:2}],
[{x: 1, y:1}, {x:2, y:1}, {x:3,y:1}],
]
class Game extends React.Component {
renderGrid() {
return _.map(GRID, row =>{
_.map(row, cell =>{
return <div style={{height: 100 + 'px', width: 100+ 'px'}}> {cell.x}, {cell.y} </div>
})
})
}
render() {
return (
<div className="game">
{this.renderGrid()}
</div>
)
}
}
export default Game;
You are not returning the inner map result, once you do that it will work
renderGrid() {
return _.map(GRID, row =>{
return _.map(row, (cell, index) =>{
return <div key={index} style={{height: 100 + 'px', width: 100+ 'px'}}> {cell.x}, {cell.y} </div>
})
})
}
Working codesandbox
In your case, the array buildin map function should be enough.
Don't forget give an unique key for each element in the map
Tips:
items.map(item => item) is the short hand format for items.map(item => { return(item); })
If you put number in inline css style, 'px' unit will be used as default.
Based on your input:
class Game extends Component {
render() {
return (
<div className="game">
{
GRID.map((row, rowIdx) => (
row.map((cell, cellIdx) => (
<div
key={`${rowIdx}-${cellIdx}`}
style={{ height: 100, width: 100 }}
>
{cell.x}, {cell.y}
</div>
))
))
}
</div>
);
}
}
There is the codesandbox demo for this code: https://codesandbox.io/s/2px4znwopr
Hope this answer could help.
Full solution to render a grid using bootstrap:
renderGrid() {
return _.map(GRID, row => {
return <div className="row"> {_.map(row, cell => {
return <div style={{ height: 100 + 'px', width: 100 + 'px' }}> {cell.x}, {cell.y} </div>
})
} </div>
})
}

Change color of react-big-calendar events

I need to make a calendar with events and I decided to use react-big-calendar. But I need to make events of different colors. So each event will have some category and each category has corresponding color. How can I change the color of the event with react?
Result should look something like this
Sorry, I haven't read the documentation really well. It can be done with the help of eventPropGetter attribute. I've made it like this:
eventStyleGetter: function(event, start, end, isSelected) {
console.log(event);
var backgroundColor = '#' + event.hexColor;
var style = {
backgroundColor: backgroundColor,
borderRadius: '0px',
opacity: 0.8,
color: 'black',
border: '0px',
display: 'block'
};
return {
style: style
};
},
render: function () {
return (
<Layout active="plan" title="Planning">
<div className="content-app fixed-header">
<div className="app-body">
<div className="box">
<BigCalendar
events={this.events}
defaultDate={new Date()}
defaultView='week'
views={[]}
onSelectSlot={(this.slotSelected)}
onSelectEvent={(this.eventSelected)}
eventPropGetter={(this.eventStyleGetter)}
/>
</div>
</div>
</div>
</Layout>
);
}
Additional tip on how to style different kinds of events: In the myEvents array of event objects, I gave each object a boolean property isMine, then I defined:
<BigCalendar
// other props here
eventPropGetter={
(event, start, end, isSelected) => {
let newStyle = {
backgroundColor: "lightgrey",
color: 'black',
borderRadius: "0px",
border: "none"
};
if (event.isMine){
newStyle.backgroundColor = "lightgreen"
}
return {
className: "",
style: newStyle
};
}
}
/>
This solution is simple !
eventPropGetter={(event) => {
const backgroundColor = event.allday ? 'yellow' : 'blue';
return { style: { backgroundColor } }
}}
change the condition according to your need and it is done.
Siva Surya's solution is the fastest, and I have added the color property as well. Thanks...
import React, {useEffect, useLayoutEffect} from 'react';
import { Calendar, momentLocalizer,globalizeLocalizer } from 'react-big-calendar'
import moment from 'moment';
import { connect } from 'frontity';
import BackgroundWrapper from 'react-big-calendar/lib/BackgroundWrapper';
const MyCalendar = ({ actions, state, objetoBloque, formato }) => {
const localizer = momentLocalizer(moment);
const myEventsList = [
{
title: 'My Event',
start: '2022-06-21T13:45:00-05:00',
end: '2022-06-25T14:00:00-05:00',
// elcolor:'red'
colorEvento:'red'
},
{
title: 'Otro',
start: '2022-06-15T13:45:00-05:00',
end: '2022-06-23T14:00:00-05:00',
colorEvento:'green',
color:'white'
}
];
return(
<div>
<Calendar
// defaultDate = {defaultDate}
localizer={localizer}
events={myEventsList}
startAccessor="start"
endAccessor="end"
style={{ height: 500 }}
BackgroundWrapper = "red"
eventPropGetter={(myEventsList) => {
const backgroundColor = myEventsList.colorEvento ? myEventsList.colorEvento : 'blue';
const color = myEventsList.color ? myEventsList.color : 'blue';
return { style: { backgroundColor ,color} }
}}
/>
</div>
)
}
export default connect(MyCalendar);
Searching for how to change the border colour of an event also lead me here, and I couldn't find the answer anywhere else, but found that adding the following done the trick:
border: "black",
borderStyle: "solid"

Categories