Creating an array of styles in React - arrays

For certain reasons I need to create an array of different styles to eventually use at certain times. Regardless I have this bit of code...
export const carouselData = {
cdata: [{
bgimage: require('Assets/img/Banners/mybanner1.jpg')
},{
bgimage: require('Assets/img/Banners/mybanner2.jpg'),
}]
}
...
var mySectionStyle
this.props.cdata.cdata.map((carouselData, key) => (
mySectionStyle[key] = {
backgroundImage: "url(" + carouselData.bgimage + ")"
}
))
return (
{ this.props.cdata.cdata.map((carouselData, key) => (
<div className="bg_image" style={ sectionStyle[key] }>
//Some stuff here
</div>
))}
)
Now to anyone that is half decent at coding probably sees huge issues with this code but as a newbie I need help finishing it (or rewriting).
Can anyone help me create an array so I can access my styles one by one with mySectionStyle[0], mySectionStyle[1], mySectionStyle[2] etc
Edit. I have an array that has many images in it and I want those in an array so I can set the carousel up with different background images.

Why can't you just do:
var mySectionStyle = {
style1: {
margin: 0,
},
style2: {
margin: 10,
},
}
const style1 = mySectionStyle['style1'];
const style2 = mySectionStyle['style2'];
If you later need it in an array, you can use the Object methods to convert it.
const availableStyles = Object.keys(mySectionStyle); // ['style1', 'style2']
availableStyles.forEach(style => mySectionStyle[style].backgroundImage = `url(${carouselData.bgimage})`;);
See also Object.values and Object.entries for other conversion to array options.

Related

How to type this object with Typescript

In the following example, I'm not sure what the type should be for the style variable:
export const getPaddingOrMarginStyle = (arrValue: number[], key: string) => {
// The key can only contain "margin" and "padding"
const style = {}; // <--------------- what is type??
if (arrValue.length === 4) {
style.key = `${arrValue[0]}px ${arrValue[1]}px ${arrValue[2]}px ${arrValue[3]}px`;
}
if (arrValue.length === 2) {
style[key] = `${arrValue[0]}px ${arrValue[1]}px`;
}
if (arrValue.length === 1) {
style[key] = `${arrValue}px`;
}
if (arrValue.length === 1 && key === 'margin') {
if (arrValue[0] === 0) {
style.margin = `${arrValue}px auto`;
} else {
style.margin = `${arrValue}px`;
}
}
return style; // i want result style { margin: '10px 10px 10px 10px'} or { padding: '10px 10px 10px 10px'}
};
One way to do this is:
type MyStyle = {
margin?: string;
padding?: string;
}
And then use it as such:
const style: MyStyle = {};
You can get by without writing a function to add style such as padding and margin.
While I don't know your technical problem, I would say start small, with simple css classes and use those classnames in your TypeScript components.
Once you get the hang of it, you can make the code more complex and push for functions to do more complex styles that are based on conditions.
Good luck on your TypeScript learning journey.
A quick search lead me to this stack overflow: Type for style attribute passed to function.
Looks like the type is React.CSSProperties.

Rendering .map of object to change its properties

I'm new to React js & React Native please help
so i have this data of partners
const [lessorPartners , setLessorPartners] = useState(null)
const dataPartnerBeforeFetch = [
{id:1, name:"BFI" , img:"lessor1" , code:"PU77"},
{id:2, name:"SMF" , img:"lessor2" , code:"TT38"},
{id:3, name:"Adira" , img:"lessor3" , code:"PT74"},
{id:4, name:"BFI" , img:"lessor1" , code:"PB63"},
{id:5, name:"SMF" , img:"lessor2" , code:"BU42"},
{id:6, name:"Adira" , img:"lessor3" , code:"AL39"}
]
useEffect(() =>{
if(dataPartnerBeforeFetch ){
dataPartnerBeforeFetch.map(dataPartner=>{
dataPartner.color = false
})
setLessorPartners(dataPartnerBeforeFetch)
}
},[dataPartnerBeforeFetch ])
I added color to its end if its true then it will turn transparent / false it will be orange
and I tried to loop it :
and render it all with these functions
const renderingPartners = () => {
return(
lessorPartners.map(lessorPartner => {
renderingPartner(lessorPartner)
})
)
}
const renderingPartner = (lessorPartner) =>{
return(
<div style={{backgroundColor: false ? 'orange' : 'transparent'}}
onClick={()=>{
onClickParter(lessorPartner);
}}
>
<LessorPartner
key = {lessorPartner.id}
object = {lessorPartner}
/>
</div>
)
}
and i tried to call renderingPartners() in my app .js like this
<div>
{ lessorPartners && renderingPartners()}
</div>
but no component returned, just empty and no error
the next idea is to change it's color on click with this function and re render the whole mapping
const onClickParter = (q) =>{
q.color = !q.color
let index = lessorPartners.indexOf(q);
lessorPartners[index]= q
setLessorPartners(lessorPartners)
renderingPartners()
}
just like radio button with list of lessor that i've tried to map
please help i've been stuck here for hours
So map function returns a new array (also it returns a value so if you are specifying braces you have to explicitly write return). you should modify your first snippet like this:
let _dataPartnerBeforeFetch = dataPartnerBeforeFetch.map(dataPartner=>{
return {
...dataPartner,
color : false
}
});
setLessorPartners(_dataPartnerBeforeFetch)
Similarly this snippet should be corrected like this:
lessorPartners.map(lessorPartner => renderingPartner(lessorPartner))
Edited:
Why the color change is not reflected?
Its almost always best to return a new array.
const onClickParter = (q) =>{
let _lessorPartners = lessorPartners.filter(f=> !(f.indexOf(q) >= 0));
_lessorPartners.push({
...q,
color : !q.color
});
setLessorPartners(_lessorPartners);
//renderingPartners();
//we donot have to explicity call the function to enforce rerender because it's already binded by a state variable. So setting the state would do the trick.
}
Here filter returns a new copy of the array without the item in scope (reffered to as 'q'). Then you add a new object with the inverted color to the new array and set the state.

Need dynamic icon for MarkerClusterer in #react-google-maps/api

TL;DR: In #react-google-maps/api, I want to be able to make dynamic cluster icons/symbol in the style of pie charts, based on the markers in the cluster, but it seems I can only make icons from a static array, and cannot pass the the markers as parameters.
Full Description:
I am using typescript react with the package #react-google-maps/api, and I'm trying to find a way with the ClustererComponent/MarkerClusterer to take a callback or similar in order to be able to be able to create an svg for each cluster based on the markers in the given cluster.
The current issue is that the way I understand it, I am limited to a static array of urls to icons, and thought I can make an svg in those, I have no way to pass parameters into those svgs, as the only way the package allows me to chose a style is thought index in the style array.
I have read thought the following material, but have not been able to get find a way to make an icon dynamically based on the markers:
Documentation for #react-google-maps/api: https://react-google-maps-api-docs.netlify.app/#markerclustere
Documentation for google maps markerclusterer: https://developers.google.com/maps/documentation/javascript/marker-clustering
I have found libraries like this: https://github.com/hassanlatif/google-map-chart-marker-clusterer, that should be able to be used as a solution, but they don't seem to work with the #react-google-maps/api, only with earlier versions of google map. If this is not the case, and these can be used directly, then I would be more then happy with an answer describing how to use libraries like the one above with #react-google-maps/api, as that should allow be to make clusters in the same way as the picture below.
EDIT: as I got reminded in the comments, here is the code I have so far:
What I've tried: I have tried to find any way to set in an svg element instead of a url, but have since just decided to make a url with the svg data, as shown below. I have tried to edit the url of the clusters under the MarkerClusterer thought the callback for onClusteringBegin, onClusteringEnd and onLoad, but so far, no luck.
How I make the svg into url-data, so it can be used for img src
/*
* Pie Chart SVG Icon in URL form
*
* Inspiration taken from: https://medium.com/hackernoon/a-simple-pie-chart-in-svg-dbdd653b6936
*
* Note: As of right now, I am identifying the difference in marker types by setting the type-number I use in the title of the marker
*/
const serializeXmlNode = (xmlNode: any) => {
if (typeof window.XMLSerializer != "undefined") {
return (new window.XMLSerializer()).serializeToString(xmlNode);
} else if (typeof xmlNode.xml != "undefined") {
return xmlNode.xml;
}
return "";
}
function getCoordinatesForPercent(percent: number) {
const x = Math.cos(2 * Math.PI * percent);
const y = Math.sin(2 * Math.PI * percent);
return [x, y];
}
const makePieChartIcon = (slices: any[]) => {
const svgNS = 'http://www.w3.org/2000/svg';
var svg = document.createElementNS(svgNS, 'svg')
svg.setAttribute('viewBox', '-1.1 -1.1 2.2 2.2')
svg.setAttribute('style', 'transform: rotate(-90deg)')
svg.setAttribute('height', '60')
var circle = document.createElementNS(svgNS, 'circle')
circle.setAttribute('r', '1.1')
circle.setAttribute('fill', 'white')
svg.appendChild(circle);
let cumulativePercent = 0;
slices.map((slice: any) => {
const [startX, startY] = getCoordinatesForPercent(cumulativePercent);
cumulativePercent += slice.percent;
const [endX, endY] = getCoordinatesForPercent(cumulativePercent);
const largeArcFlag = slice.percent > .5 ? 1 : 0;
const pathData = [
`M ${startX} ${startY}`, // Move
`A 1 1 0 ${largeArcFlag} 1 ${endX} ${endY}`, // Arc
`L 0 0`, // Line
].join(' ');
const path = document.createElementNS(svgNS, 'path');
path.setAttribute('d', pathData);
path.setAttribute('fill', slice.color);
svg.appendChild(path);
})
var svgUrl = 'data:image/svg+xml;charset=UTF-8,' + serializeXmlNode(svg)
return svgUrl
}
const makeDynamicClusterIcon = (markers: any[]) => {
var numMarkers = markers.length;
var slices = markers.reduce((acc: any, marker: any) => {
acc[parseInt(marker.title)].percent += 1 / numMarkers;
return acc;
}, [
{ percent: 0, color: 'Green' },
{ percent: 0, color: 'Blue' },
{ percent: 0, color: 'Red' },
])
var newIconURL = makePieChartIcon(slices)
return newIconURL;
}
How I use the MarkerClusterer Component
<MarkerClusterer
options={{
averageCenter: true,
styles: clusterStyles,
}}
>
{(clusterer) =>
markerData.map((marker: any) => (
<Marker
key={marker.key}
title={String(marker.type)}
position={{ lat: marker.lat, lng: marker.lng }}
clusterer={clusterer}
/>
))
}
</MarkerClusterer>
Right now, I can only use some static styles, but I have them as the following for testing:
const clusterStyles = [
{
height: 50, textColor: '#ffffff', width: 50,
url: 'data:image/svg+xml;charset=UTF-8,%3Csvg xmlns="http://www.w3.org/2000/svg" height="50" width="100"%3E%3Ccircle cx="25" cy="25" r="20" stroke="black" stroke-width="3" fill="green" /%3E%3C/svg%3E',
},
{
height: 50, textColor: '#ffffff', width: 50,
url: 'data:image/svg+xml;charset=UTF-8,%3Csvg xmlns="http://www.w3.org/2000/svg" height="50" width="100"%3E%3Ccircle cx="25" cy="25" r="20" stroke="black" stroke-width="3" fill="red" /%3E%3C/svg%3E',
}
];
I found a solution, by finding out that the style array for each cluster (ClusterStyles) can be changed, and then I have change it with the data from the specific markers in the given cluster. I ended up doing this in the callback onClusteringEnd, as here:
{/* Added to the MarkerClusterer */}
onClusteringEnd={(clusterer) => {
clusterer.clusters.map((cluster) => {
cluster.clusterIcon.styles = makeDynamicClusterIcon(cluster.markers)
})
}}
And I changed the last line with return of the makeDynamicClusterIcon function I showed above to instead say:
return [{ url: newIconURL, height: 60, width: 60, textColor: '#FFFFFF', textSize: 22 }];

Wrapping an an html anchor tag around an array is causing unexpected results in my React component

I have a component that I use in my react app that generates a random game on the screen.
It's working, but now I'm trying to add some html into the game title.
When I do that, my game titles come up as:
[object Object]
Here is where I generate a random game:
const newGame = () => {
return {
title: gameTitleArray[Math.floor(Math.random() * gameTitleArray.length)],
type: gameTypeArray[Math.floor(Math.random() * gameTypeArray.length)],
startDate: getDate(new Date(2019, 0, 1), new Date()),
endDate: getDate(new Date(2022, 0, 1), new Date()),
}
}
You can see I'm trying to wrap an html anchor tag around the 'title' portion.
Here is how I'm exporting the component:
export default function makeGameData(...lens) {
const makeGameDataLevel = (depth = 0) => {
const len = lens[depth]
return range(len).map(d => {
return {
...newGame(),
subRows: lens[depth + 1] ? makeGameDataLevel(depth + 1) : undefined,
}
})
}
return makeGameDataLevel()
}
Here is an example of the gameTypeArray:
const gameTypeArray = ['RPG', 'Western', 'Real-Time Strategy', 'Fantasy', 'First Person Shooter']
And an example of gameTitleArray:
const gameTitleArray = ['Future Agent','Human Universe','Chase of Resitution','Destroy of Resitution','Days and Glitch','Mayhem and Faith','Dynaworks','Crystalback','Fusionheart','Hellscape']
I even tried creating a separate function like this:
function gameTitleArrayLink() {
const gameTitleArray = ['Future Agent','Human Universe','Chase of Resitution','Destroy of Resitution','Days and Glitch','Mayhem and Faith','Dynaworks','Crystalback','Fusionheart','Hellscape']
const title = gameTitleArray[Math.floor(Math.random() * gameTitleArray.length)]
const titleUrl = {title}
return <div dangerouslySetInnerHTML={{ __html: titleUrl }} />
}
And then setting the title like this:
title: researchSummaryList()
Obviously I'm doing something wrong, but I'm not getting any errors, just the [object Object]
Is there anything I'm doing wrong?
Thanks!
Try wrapping the array value in {} to have it treated as an expression:
{gameTitleArray[Math.floor(Math.random() * gameTitleArray.length)]}
I think that the item you want to render
(gameTitleArray[Math.floor(Math.random() * gameTitleArray.length)])
is an object and not a string

ReactJS: Child Component is not updating even I am passing different values

I am new to React.
My child component (SmithchartSeriesDirective) successfully displays the data passed from the server, when the parent component (SimplePanel) is loaded for the first time. On subsequent calls the data received from server changes, it is reflected in the props, but once I bind this data to the child component, it does not reflect the updated data in the component.
I am binding the data in listResult array.
Below is Parent Component SimplePanel
export class SimplePanel extends Component<Props> {
render() {
var reactance: number[] = [];
var resistance: number[] = [];
this.props.data.series.map((anObjectMapped, index) => {
if(index==0)
{
reactance = anObjectMapped.fields[0].values.toArray();
}
else
{
resistance = anObjectMapped.fields[0].values.toArray();
}
});
var resultArr =
{
resistance:0,
reactance:0
};
let listResult =[];
for (let index = 0; index < resistance.length; index++) {
var newObj = Object.create(resultArr);
newObj.resistance = Number(resistance[index]);
newObj.reactance=reactance[index];
listResult.push(newObj);
}
return (<div className='control-pane' style={{ height:'100%', width:'100%', backgroundColor:'#161719' }} >
<div className='col-md-12 control-section' style={{ height:'100%', width:'100%' }}>
<SmithchartComponent id='smith-chart' theme="MaterialDark" legendSettings={{ visible: true, shape: 'Circle' }}>
<Inject services={[SmithchartLegend, TooltipRender]}/>
<SmithchartSeriesCollectionDirective>
<SmithchartSeriesDirective
points= {listResult}
enableAnimation={true}
tooltip={{ visible: true }}
marker={{ shape: 'Circle', visible: true, border: { width: 2 } }}
>
</SmithchartSeriesDirective>
</SmithchartSeriesCollectionDirective>
</SmithchartComponent>
</div>
</div>);
welcome to stack overflow.
First remember that arrays saved by reference in JavaScript. So if you change any array by push() or pop() methods, reference to that array doesn't change and React can't distinguish any change in your array (to re-render your component).
let a = [2];
let b = a;
b.push(4);
a == b; //a is [2] and b is [2,4] but the result is true.
You can use this approach as a solution to this problem:
let listResult = [...oldListResult, newObj]; // ES6 spread operator
Also consider for rendering array elements you need to use key prop, so React can render your components properly. more info can be found here.

Resources