What does the "ref" do in this React code - reactjs

I'm a beginner and read lots of code and this one I cant find any docs on
How does that work I cant see that ref is used in the Slider or maybe it is
The file:
/* eslint-disable react/jsx-props-no-spreading */
import Slider from 'react-slick';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
import React from 'react';
import Resume from '../../resume.json';
import albums from '../../albumData.json';
const la = require('lodash');
class SliderWrapper extends React.Component {
shouldComponentUpdate(nextProps) {
// certain condition here, perhaps comparison between this.props and nextProps
// and if you want to update slider on setState in parent of this, return true, otherwise return false
const { updateCount } = nextProps;
const { updateCounter } = this.props;
if (updateCounter !== updateCount) {
return false;
}
return true;
}
sliders() {
return Resume.weeks.map(week => {
let photo = la.find(albums, { weekNumber: week.weekNumber });
photo = encodeURIComponent(`${process.env.PUBLIC_URL}/images/weeks/${week.weekNumber}/${photo.coverImage}`);
const { onImageClick } = this.props;
return (
// Timeline items
<section className="timeline-carousel" key={week.weekNumber}>
<h1>week {week.weekNumber}</h1>
<div className="timeline-carousel__item-wrapper" data-js="timeline-carousel">
<div className="timeline-carousel__item">
<div className="timeline-carousel__image">
<img onClick={() => onImageClick(week.weekNumber)} alt="CoverImage" src={photo} />
<h2>UNDER CONSTRUCTION IN PROGRES..</h2>
</div>
<div className="timeline-carousel__item-inner">
<div className="pointer" />
<span className="year">{week.year}</span>
<span className="month">{week.albumDate}</span>
<p>{week.summary}</p>
<a href="#/" className="read-more">
Read more, Dev should go to read more
</a>
</div>
</div>
</div>
</section>
);
});
}
render() {
const { afterChanged } = this.props;
const { beforeChanged } = this.props;
const settings = {
dots: false,
arrows: false,
autoplay: false,
infinite: true,
lazyLoad: false,
swipeToSlide: true,
centerMode: false,
focusOnSelect: false,
className: 'center',
slidesToShow: 4,
afterChange: afterChanged,
beforeChange: beforeChanged,
responsive: [
{
breakpoint: 1024,
settings: {
slidesToShow: 3,
slidesToScroll: 3,
infinite: false,
},
},
{
breakpoint: 600,
settings: {
slidesToShow: 2,
slidesToScroll: 2,
initialSlide: 2,
},
},
{
breakpoint: 480,
settings: {
slidesToShow: 1,
slidesToScroll: 1,
},
},
],
};
return (
<div>
<Slider
ref={slider => {
this.slider = slider;
}}
{...settings}
>
{this.sliders()}
</Slider>
</div>
);
}
}
export default SliderWrapper;

Refs provide a way to access DOM nodes or React elements created in the render method.
Checkout ReactJS Docs for more information

Related

How to customise react-google-charts?

I want to customise legends and title of x-Axis and y-Axis in my bar graph. It is a react google chart. Here is my current graph having slanted legends, I want it to be as a graph in second image.
Here is the code for bar graph chart that I want to use.
slanted legend bar graph
required bar graph
'''
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Chart from 'react-google-charts';
import Loader from 'semantic-ui-react/dist/commonjs/elements/Loader';
import Dimmer from 'semantic-ui-react/dist/commonjs/modules/Dimmer';
import ErrorMessage from '../vizTab/ErrorMessage';
class BarGraph extends Component {
state = {}
componentDidUpdate = (prevProps) => {
const { loading, data } = this.props;
if (prevProps.loading !== loading && !loading) {
this.processResponse(data);
}
}
processResponse = (data) => {
try {
const keys = Object.keys(data[0] || {});
const renderArray = [keys].concat(data.map((d) => (
keys.map((key) => d[key])
)));
this.setState({ data: renderArray });
} catch (error) {
this.setState({ data: undefined });
}
}
clicked = (row) => {
const { clicked, data } = this.props;
if (clicked) clicked(data[row]);
}
render = () => {
const {
xAxis, yAxis, orientation, slantedTextAngle, loading, colors, noDataMessage, fullWidth,
groupWidth,
} = this.props;
const { data } = this.state;
let chartType = '';
if (orientation === 'horizontal') {
chartType = 'BarChart';
} else {
chartType = 'ColumnChart';
}
return (
<div
className="container-text large ui card centered"
style={{
height: '100%', width: '100%', boxShadow: 'none', WebkitBoxShadow: 'none',
}}
>
{loading ? (
<Dimmer active inverted>
<Loader>Loading</Loader>
</Dimmer>
) : (
!data || (data && data.length <= 1) ? (
<ErrorMessage noDataMessage={noDataMessage} />
) : (
<Chart
width="100%"
height="100%"
chartType={chartType}
loader={<div>Loading Chart</div>}
data={data}
options={{
hAxis: {
title: xAxis,
legend: { alignment: 'center' },
slantedText: true,
slantedTextAngle: parseInt(slantedTextAngle, 10),
minValue: 0,
},
vAxis: {
title: yAxis, minValue: 0,
},
colors: colors.split(',') || [],
bar: { groupWidth: groupWidth || data.length > 4 ? '60%' : '30%' },
animation: {
duration: 300,
easing: 'linear',
startup: true,
},
chartArea: fullWidth === 't' ? {
left: '50%', width: '80%',
} : undefined,
}}
chartEvents={[
{
eventName: 'ready',
callback: ({ chartWrapper, google }) => {
const chart = chartWrapper.getChart();
google.visualization.events.addListener(
chart,
'click',
(e) => {
const { targetID } = e;
if (targetID && targetID.match('legend')) {
return;
}
const [, row] = targetID.match(/[0-9]+/g) || [];
if (row >= 0) this.clicked(row);
},
);
},
},
]}
/>
)
)}
</div>
);
}
}
BarGraph.propTypes = {
loading: PropTypes.bool,
data: PropTypes.arrayOf(PropTypes.any),
clicked: PropTypes.func,
xAxis: PropTypes.string,
yAxis: PropTypes.string,
orientation: PropTypes.string,
slantedTextAngle: PropTypes.string,
colors: PropTypes.string,
noDataMessage: PropTypes.string,
fullWidth: PropTypes.string,
groupWidth: PropTypes.string,
};
BarGraph.defaultProps = {
loading: false,
data: [],
clicked: null,
xAxis: '',
yAxis: '',
orientation: 'vertical',
slantedTextAngle: '30',
colors: 'green,blue,purple,whisper,red,dodger blue,dark green,maroon,yellow,grey,orange,pink,magenta,teal,brown',
noDataMessage: '',
fullWidth: null,
groupWidth: null,
};
export default BarGraph;
'''

How to update nested array and objects in react

I'm trying to update the state in react. However, still not clear how shall I do it. The nested structure is something like :
this.state ={
permissionsObject:{
fruitsGroup:[
{
index:0,
taste:false,
color:false,
},
{
index:1,
taste:false,
color:false,
},
],
fruitsGroup:[
{
index:0,
taste:false,
color:false,
},
{
index:1,
taste:false,
color:false,
},
]
}
}
Now, if I want to update the value of fruitsGroup -> taste based on the index value then how shall I proceed. I found there are various solutions exists for nested structure. However, none of them were answering my query or they are using react hooks while I'm not. Thanks well in advance.
Edit: The fruitGroup will have different name. So, how can I even locate it dynamically while setting the state.
You can do it like this:
import React, { Component } from "react";
export class App extends Component {
state = {
permissionsObject: {
fruitsGroup: [
{
index: 0,
taste: false,
color: false,
},
{
index: 1,
taste: false,
color: false,
},
],
groupName: [
{
index: 0,
taste: false,
color: false,
},
{
index: 1,
taste: false,
color: false,
},
],
},
};
updateStateHandler = (idx) => {
const updatedFruitsGroup = this.state.permissionsObject.fruitsGroup.map(
(item) => (item.index === idx ? { ...item, taste: true } : item)
);
const newState = {
permissionsObject: {
...this.state.permissionsObject,
fruitsGroup: updatedFruitsGroup,
},
};
this.setState(newState);
};
render() {
return (
<div>
{JSON.stringify(this.state)}
<button onClick={() => this.updateStateHandler(0)}>
Update index 0
</button>
<button onClick={() => this.updateStateHandler(1)}>
Update index 1
</button>
</div>
);
}
}
export default App;

How to customize border style on React Chart.js 2

I am trying to add dashed border to my bar charts. I am following this example here- https://jsfiddle.net/jt100/ghksq1xv/3/
I am not getting much luck I have followed the instruction very carefully and passing in the correct values but I am not adding the dashed border to my bar chart. Any help will be very much appreciated
This is what I have done
1) passed in 4 arguments: my chart instance, dataset, data and dash
```
this.dashedBorder(myLineChart, 0, 2, [15, 10]);
2) This is my function.
dashedBorder(chart, dataset, data, dash) {
chart.config.data.datasets[dataset]._meta[0].data[data].draw = function() {
chart.chart.ctx.setLineDash(dash);
Chart.elements.Rectangle.prototype.draw.apply(this,
arguments,
);
};
}
3) my whole react component. You can see what I have done here.
import React, { PureComponent } from "react";
import classes from "./YourLineGraph.module.css";
import Chart from "chart.js";
let myLineChart;
let myChartRef;
let ctx;
//--Chart Style Options--//
// Chart.defaults.global.defaultFontFamily = "'PT Sans', sans-serif";
Chart.defaults.global.defaultFontFamily = "'Cooper Hewitt'";
Chart.defaults.global.legend.display = false;
Chart.defaults.global.elements.line.tension = 0;
Chart.defaults.global.scaleLineColor = "tranparent";
Chart.defaults.global.tooltipenabled = false;
//--Chart Style Options--//
export default class YourLineGraph extends PureComponent {
chartRef = React.createRef();
componentDidMount() {
this.buildChart();
}
componentDidUpdate() {
this.buildChart();
}
buildChart = () => {
myChartRef = this.chartRef.current.getContext("2d");
ctx = document.getElementById("myChart").getContext("2d");
const { data, average, labels, attribute } = this.props;
if (typeof myLineChart !== "undefined") myLineChart.destroy();
myLineChart = new Chart(myChartRef, {
type: "bar",
data: {
//Bring in data
labels:
labels.length === data.length
? labels
: new Array(data.length).fill("Data"),
datasets: [
{
label: "Sales",
data: data,
borderColor: "#98B9AB",
borderWidth: 3,
borderStyle: "dash" //has no effect
}
]
},
options: {
plugins: {
datalabels: {
formatter: function(value, context) {
return attribute === "pounds" ? `£ ${value}` : value;
},
anchor: "end",
align: "end",
color: "#888"
}
},
scales: {
yAxes: [
{
gridLines: {
drawBorder: false,
display: false
},
ticks: {
display: false //this will remove only the label
}
}
],
xAxes: [
{
gridLines: {
drawBorder: false,
display: false
},
ticks: {
display: false //this will remove only the label
}
}
]
}
}
});
this.dashedBorder(myLineChart, 0, 2, [15, 10]);
};
dashedBorder(chart, dataset, data, dash) {
chart.config.data.datasets[dataset]._meta[0].data[data].draw = function() {
chart.chart.ctx.setLineDash(dash);
Chart.elements.Rectangle.prototype.draw.apply(this, arguments);
chart.chart.ctx.setLineDash([1, 0]);
};
}
render() {
return (
<div className={classes.graphContainer}>
<canvas id="myChart" ref={this.chartRef} />
</div>
);
}
}

ComponentDidUpdate causing infinite render even when wrapped in condition

I'm trying to pull some data from Google Analytics reporting API and display the data inside the apex charts library. I managed to successfully do this. However, I now want filtering options to where if the user selects a certain date within the date range picker react wrapper, the apex charts data gets updated from the API.
I'm struggling figuring out on how when my data gets updated, to update the state with the new state within my life cycle method? I think I'm doing something minor I just don't know what it is. I looked up the documentation on the life cycle method and it says to make sure to wrap it inside a condition which I did. However, when the else condition is met, it causes an infinite render.
Here is my code: (the bug i'm stuck on is the componentWillUpdate lifecycle method) everything else works fine.
import React from "react";
import Header from "../common/Header";
import Footer from "../common/Footer";
import moment from "moment";
import $ from "jquery";
import ApexCharts from "apexcharts";
import Chart from "react-apexcharts";
import DateRangePicker from "react-bootstrap-daterangepicker";
const VIEW_ID = "";
class Charts extends React.Component {
constructor(props) {
super(props);
this.printResults = this.printResults.bind(this);
this.pageViews = this.pageViews.bind(this);
this.handleError = this.handleError.bind(this);
this.state = {
loading: true,
filterstartDate: "",
filterendDate: "",
// Start Series Bar State
ChartOne: {
chart: {
id: "ChartOne"
},
colors: ["#e31d1a"],
xaxis: {
categories: [],
labels: {
style: {
colors: []
}
},
title: {
text: "Locations"
}
},
yaxis: {
labels: {
style: {
colors: []
}
},
title: {
text: "Count"
}
}
},
ChartOneSeries: [],
}
pageViews = async () => {
window.gapi.client
.request({
path: "/v4/reports:batchGet",
root: "https://analyticsreporting.googleapis.com",
method: "POST",
body: {
reportRequests: [
{
viewId: VIEW_ID,
dateRanges: [
{
startDate: "7daysAgo",
endDate: "today"
}
],
metrics: [
{
expression: "ga:pageviews"
}
],
dimensions: [
{
name: "ga:country"
}
],
orderBys: [{ fieldName: "ga:pageviews", sortOrder: "DESCENDING" }]
}
]
}
})
.then(this.printResults, this.handleError);
};
componentDidMount() {
$.getScript("https://apis.google.com/js/client:platform.js").done(() => {
window.gapi.signin2.render("my-signin2", {
scope: "profile email",
width: 240,
height: 50,
longtitle: true,
theme: "dark",
onsuccess: this.pageViews,
onfailure: this.handleError
});
});
}
//log the data
printResults(response) {
let pageviewLocation = [];
let pageviewCount = [];
let pageviewTotal = response.result.reports[0].data.totals[0].values[0];
let totalComma = pageviewTotal
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
response.result.reports[0].data.rows.map(value => {
//console.log(value.dimensions);
pageviewLocation.push(value.dimensions[0]);
pageviewCount.push(parseInt(value.metrics[0].values[0]));
});
//console.log(total);
this.setState({
loading: false,
ChartOne: {
title: {
text: totalComma,
align: "center",
style: {
fontSize: "20px"
}
},
subtitle: {
text: "Total Page Views",
align: "center",
style: {
fontSize: "14px",
cssClass: "apexcharts-yaxis-title"
}
},
plotOptions: {},
...this.state.ChartOne,
xaxis: {
width: 1,
...this.state.ChartOne.xaxis,
labels: {
show: false,
...this.state.ChartOne.xaxis.labels,
style: {
...this.state.ChartOne.xaxis.labels.style
}
},
categories: pageviewLocation
},
yaxis: {
min: 0,
...this.state.ChartOne.yaxis,
labels: {
//show: false,
...this.state.ChartOne.yaxis.labels,
style: {
...this.state.ChartOne.yaxis.labels.style
}
}
}
},
ChartOneSeries: [
{
name: "Total Page Views",
data: pageviewCount
}
]
});
}
componentDidUpdate(prevProps, prevState) {
if (this.state.filterstartDate === "" && this.state.filterendDate === "") {
console.log("they are empty");
} else {
this.setState({
// this fails immediately once the condition is met
test: "success!"
});
}
}
Datepicker = async (event, picker) => {
this.setState({
filterstartDate: moment(picker.startDate._d).format("YYYY-MM-DD"),
filterendDate: moment(picker.endDate._d).format("YYYY-MM-DD")
});
//console.log(this.state);
};
//or the error if there is one
handleError(reason) {
console.error(reason);
console.error(reason.result.error.message);
}
render() {
//console.log();
return (
<div className="containerfluid" id="fullWidth">
<Header />
<div className="container" id="chartContainer">
<h1>Site Analytics</h1>
<div className="row">
<div className="col-md-12">
<DateRangePicker
startDate={moment().format("MM-DD-YYYY")}
endDate={moment().format("MM-DD-YYYY")}
onApply={this.Datepicker}
>
<button className="btn btn-info">
<i className="fas fa-filter">
<span
style={{
fontFamily: "Roboto, san-serif",
fontWeight: "normal",
padding: "5px"
}}
>
Filter Date
</span>
</i>
</button>
</DateRangePicker>
</div>
</div>
<div className="row">
<div className="col-md-4">
{/* Chart One Line */}
{this.state.loading ? (
<React.Fragment>
<i className="fas fa-spinner fa-3x" id="loader" /> Please wait
...!
</React.Fragment>
) : (
<div className="chartContainer">
<Chart
options={this.state.ChartOne}
series={this.state.ChartOneSeries}
type="line"
width={400}
height={300}
/>
</div>
)}
</div>
</div>
<div id="my-signin2" />
</div>
<Footer />
</div>
);
}
}
export default Charts;
When you use setState you're triggering the lifecycle again. If you don't set your filterstartDate and filterendDate to "", you'll keep calling setState infinitely.
componentDidUpdate(prevProps, prevState) {
if (this.state.filterstartDate === "" && this.state.filterendDate === "") {
console.log("they are empty");
} else {
this.setState({
filterstartDate: "",
filterendDate: "",
test: "success!"
});
}
}

React-slick hide pagination dots on last slide

I am using React-Slick component in my project. I have to show pagination dots on all the slides except the last slide. I want to hide those pagination dots for last slide.
I have checked that afterChange function is available as a callback. This can be used to customise the slider css in jQuery, but how can I use this function to hide the pagination dots in React application?
import Slider from 'react-slick';
export default class Carousal extends Component {
render() {
let settings = {
accessibility: true,
dots: true,
infinite: false,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
centerMode: true,
centerPadding: '10px',
responsive: [{
breakpoint: 768,
settings: {
swipeToSlide: true
}
}],
afterChange: function (currentSlide) {
console.log(currentSlide);
}
};
return (
<Slider {...settings} >
{slides}
</Slider>
);
}
On Components construction set state value for dots prop for the Slider component. Then set it to false when you don't want to show it.
export default class Carousal extends Component {
constructor(props) {
super(props);
this.state = {
dots: true
};
}
render() {
let settings = {
accessibility: true,
dots: this.state.dots,
infinite: false,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
centerMode: true,
centerPadding: '10px',
responsive: [{
breakpoint: 768,
settings: {
swipeToSlide: true
}
}],
afterChange: (currentSlide) => {
console.log(currentSlide);
this.setState({
dots: (currentSlide !== 'yourDesiredSlide')
});
}
};
return (
<Slider {...settings} >
{slides}
</Slider>
);
}

Resources