Ag-grid custom tooltip with functional component - reactjs

I am looking at ag-Grid's example on creating a custom tooltip.
import React, {Component} from 'react';
export default class CustomTooltip extends Component {
getReactContainerClasses() {
return ['custom-tooltip'];
}
render() {
const data = this.props.api.getDisplayedRowAtIndex(this.props.rowIndex).data;
return (
<div className="custom-tooltip" style={{backgroundColor: this.props.color || 'white'}}>
<p><span>{data.athlete}</span></p>
<p><span>Country: </span> {data.country}</p>
<p><span>Total: </span> {data.total}</p>
</div>
);
}
}
According to ag-Grid's react component page, "If you wish to override the style of this div you can either provide an implementation of the ag-react-container class, or via the getReactContainerStyle or getReactContainerClasses callbacks on the React component:"
How would I go about creating a custom tooltip using a functional component? I am not sure how I would provide an implementation of the getReactContainerClasses callback.

You won't be able to have the public function getReactContainerClasses in a functional component, you'd need to write a class component. If you want to write a functional component, just set the CSS class directly on the container DOM element, similarly to their vanilla JS example. Below is a functional tooltip example which sets the class custom-tooltip.
import React, {Component} from 'react';
export const FunctionalCustomTooltip = (props) => {
props.reactContainer.classList.add('custom-tooltip');
const data = props.api.getDisplayedRowAtIndex(props.rowIndex).data;
return (
<div className="custom-tooltip" style={{backgroundColor: props.color || 'white'}}>
<p><span>{data.athlete}</span></p>
<p><span>Country: </span> {data.country}</p>
<p><span>Total: </span> {data.total}</p>
</div>
);
};
Fully working example:
https://plnkr.co/edit/WHEgtw0YVia1BVP4SVO8?p=preview

You can have public function using React Hooks with useImperativeHandle hook.
export const Component = forwardRef((props: ComponentParams, ref: any) => {
useImperativeHandle(ref, () => {
return {
getReactContainerClasses() {
return ['grid-container'];
},
};
});
}

Related

How to convert from functional component to a class component?

Hi I'm making a speech recognition for my collaborative whiteboard. My whiteboard component is a class component and I want to put the code of the speech recognition (which is a functional component), in the whiteboard component. But for that I need it to be converted to a class component. I am using library react-speech-recognition
This is the code which needs to be converted:
import React from 'react'
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition'
const Mic = () => {
const { transcript, resetTranscript } = useSpeechRecognition()
if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
return null
}
return (
<div>
<button onClick={SpeechRecognition.startListening}>Start</button>
<button onClick={SpeechRecognition.stopListening}>Stop</button>
<button onClick={resetTranscript}>Reset</button>
<p>{transcript}</p>
</div>
)
}
export default Mic
Can anyone show me how to do it? With the speech recognition function at the transcript and resetTranscript variable makes it harder for me.
You have a problem with your hook useSpeechRecognition, you can't use it inside the class component, you can check the React doc to verify: Hooks FAQ, as an alternative you should use HOC SpeechRecognition:
import React, { Component } from 'react'
import SpeechRecognition from 'react-speech-recognition'
class Mic extends Component {
render() {
const { transcript, resetTranscript, browserSupportsSpeechRecognition } = this.props
if (!browserSupportsSpeechRecognition) {
return null
}
return (
<div>
<button onClick={SpeechRecognition.startListening}>Start</button>
<button onClick={SpeechRecognition.stopListening}>Stop</button>
<button onClick={resetTranscript}>Reset</button>
<p>{transcript}</p>
</div>
)
}
}
export default SpeechRecognition(Mic)

Second class of multiple classes can't override style

button.module.css
.general_button {
width: 100%;
}
button.js
import React from 'react';
import styles from './button.module.css';
const GeneralButton = ({ text, className}) => {
return (
<button className={`${styles.general_button} ${className}`}>
<p className={styles.text}>{text}</p>
</button>
);
};
export { GeneralButton };
app.module.css
.next_btn {
width: 35%;
}
app.js
import React from 'react';
import classes from './app.module.css';
import { GeneralButton } from './components/Buttons';
const App = () => {
return (
<div>
<GeneralButton className={classes.next_btn} text='next' />
</div>
)
}
export default App;
When I used button component from app, button component is working with 'width:100%'. I would like to be button component is with 'width: 35%'.
This is when I inspect browser.
This is when I inspect browser.
Since both classes are equally specific, your app chooses whichever comes later in the stylesheet. Unfortunately you have much control over this order since it is likely generated by webpack (or whatever bundler you happen to be using).
One of the main benefits of using modular css is to avoid having to fight specificity battles such as this, so I would suggest reworking the button component slightly - something like this might work:
const GeneralButton = ({ text, variant }) => {
let buttonClass = styles.general_button;
if (variant === "next") {
buttonClass = styles.next_button;
}
return (
<button className={buttonClass}>
<p className={styles.text}>{text}</p>
</button>
);
};
The advantage here is that the button lays out the options for how to present it and the parent component just selects the type it needs. This makes it safer to re-work the button component in the future since it encapsulates all of it's states.

How to check whether React updates dom or not?

I wanted to check how to react does reconciliation so I updated the inner HTML of id with the same text. Ideally, it shouldn't update the dom but it is paint reflashing in chrome.
I have tried paint reflashing in chrome it is showing green rectangle over that same text
import React from 'react';
function App() {
return (
<div >
<p id="abc" key="help">abc is here</p>
<button onClick={function () {
// document.getElementById("may").innerHTML = "";
document.getElementById("abc").innerHTML = "abc is here";
}} > Btn</button>
</div>
);
}
export default App;
Expected result should be that paint reflashing shouldn't happen but it is happening.
You are not using React here to update the text of your p tag but directly updating the DOM with JavaScript.
So React reconciliation algorithm doesn't even run here.
In React, the output HTML is a result of the state and the props of your component.
When a change in state or props is detected, React runs the render method to check if it needs to update the DOM. So, in order to do this check, you need to store the parameters that determine your view in state or props.
Given your example, we could save the text you want to show in the p tag in the state of your component (using hooks):
import React, { useState } from 'react';
function App () {
const [text, setText] = useState('abc is here');
render() {
return (
<div >
<p id="abc" key="help">{this.state.text}</p>
<button onClick={() => setText('abc is here') }>Btn</button>
</div>
);
}
}
export default App;
If you are using a version of React that does not support hooks, you will need to transform your functional component into a class to use state:
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = { text: 'abc is here' };
}
render() {
return (
<div >
<p id="abc" key="help">{this.state.text}</p>
<button onClick={() => this.setState({ text: 'abc is here' }) }>Btn</button>
</div>
);
}
}
export default App;

React inline function in render with mobx

Can I use bind function in render with mobx? I know that this practice leads to performance degradation, but my colleague says that if we use mobx we can do bind function in render
Example:
import { inject, observer } from 'mobx-react'
#inject('store')
#observer
export default class Component extends React.Component {
render() {
const {
store: {
pushByPath,
},
} = this.props
return (
<div>
<button
onClick={() => pushByPath('param1')}
/>
<button
onClick={() => pushByPath('param2')}
/>
<button
onClick={() => pushByPath('param3')}
/>
</div>
)
}
}
if you need your function pushByPath to be bound to an instance of a store, you may follow such pattern:
import {action} from 'mobx';
class Store {
#action.bound pushByPath(path) {
// this here will always point to an instance of Store
}
}
Actually, you can use bind and really recreating function is a performance hit, but really very minimal for modern browsers. And it does not matter do you use mobx or not.

react-google-maps StandaloneSearchBox unmounting

I am trying to use the StandaloneSearchBox Component from https://www.npmjs.com/package/react-google-maps
After looking at the docs and some other answers I implemented the component like this:
import React, { Component } from "react";
import PropTypes from "prop-types";
import { withScriptjs } from "react-google-maps";
import StandaloneSearchBox from "react-google-maps/lib/components/places/StandaloneSearchBox";
import { Input } from "semantic-ui-react";
import API_KEY from "../config/googleAPIkey";
class AddressSearchbox extends Component {
constructor(props) {
super(props);
this.searchboxRef = null;
}
onSearchBoxMounted = ref => {
this.searchboxRef = ref;
};
onPlacesChanged = () => {
const places = this.searchboxRef.getPlaces();
this.props.onPlaceSelect(places[0]);
};
render() {
const Searchbox = withScriptjs(props => (
<StandaloneSearchBox
ref={props.onSearchBoxMounted}
onPlacesChanged={props.onPlacesChanged}
>
<Input
type="text"
placeholder="Type address or google place name"
icon="search"
/>
</StandaloneSearchBox>
));
return (
<Searchbox
googleMapURL={`https://maps.googleapis.com/maps/api/js?key=${API_KEY}&v=3.exp&libraries=geometry,drawing,places`}
loadingElement={<div style={{ height: `100%` }} />}
onPlacesChanged={this.onPlacesChanged}
onSearchBoxMounted={this.onSearchBoxMounted}
/>
);
}
}
AddressSearchbox.propTypes = {
onPlaceSelect: PropTypes.func.isRequired
};
export default AddressSearchbox;
I use the component in a signup form where all the other input fields update the state on input change causing re-rendering of the whole form.
When the AddressSearchbox component gets re-rendered it seems that it gets unmounted and then remounts causing flickering. The component itself works fine.
EDIT: When logging the ref parameter passed in onSearchBoxMounted() it prints null and then the SearchBox object after every re-render, so according to this the SearchBox component gets unmounted
I'm not sure if it's still actual, but to fix this you need to extract this part from the render function before your class definition:
const Searchbox = withScriptjs(props => (....))
So it will look like this:
imports ...
const Searchbox = withScriptjs(props => (....))
class AddressSearchbox extends Component {
...
render() {
return (
<Searchbox .../>
);
}
}
In practice, most React apps only call ReactDOM.render() once.
Source: https://reactjs.org/docs/rendering-elements.html
You see this flickering because ReactJS runs render() function each time when your state changes.

Resources