React Component with shared mouseOver handler - javascript

I have a simple react component that wraps the SVG 1.1 specifications recttag and adds in some defaults and looks like this:
import React, { Component } from 'react';
const defaults = {
x: 100,
y: 100,
width: 200,
height: 100,
rx: 0,
ry: 0,
};
export default class Rectangle extends Component {
constructor(props) {
super(props);
this.state = {
...defaults,
...props,
};
}
render() {
return (
<rect
{...this.state}>
{this.props.children}
</rect>
);
}
}
I am trying to find a good way to add on a mouseOver function, but would like to do it in a way that can be reused with other components similar to this.
I have looked into Higher Order Components, but am having trouble when I try to set the state, because the state is not part of the above component's state.

Related

what is the best way to setParams to navigation before setting the options for Navigation using setOptions?

I wanna know the best way to set the params and options for react native navigation in a class component.
note that the same params are used in options.
when I put all code in the constructor I got params undefined because of timing issue.
and it works. for me in one case when I added option in componentDidMount , I will write some examples in the code below.
1- first case using class component (it's working)
type Props = {
navigation: NavigationProp<any>;
route: RouteProps<{ Example: {title: string} }, 'Example'>
}
export default class Example extends Component <Props> {
constructor(props: Props){
super(props)
this.props.navigation.setParams({ title: 'title' });
}
componentDidMount(){
this.props.navigation.setOptions({ title: this.props.route.params.title })
}
...
}
2 - second case using FC: (not using this example but I think it's also the best way todo for the FC).
export function Example: React.FC = () => {
const navigation = useNavigation();
const route = useRoute();
useLayoutEffect(()=>{
navigation.setParams({ title: 'title' });
navigation.setOptions({ title: route.params.title })
})
...
}
so I hope my question is clear, is that theright way to set Header options with the lates Navigation on React Native?
constructor is the first step in component lifecycle, and you are setting params inside that, which means there is a prop that is going to be updated.
so we need a function that understands every update on a state or received props, and that listener is nothing except "componentDidUpdate(){}" 🀟:
import {NavigationProp, RouteProp} from '#react-navigation/native';
import React, {Component} from 'react';
import {Text, StyleSheet, View} from 'react-native';
type Props = {
navigation: NavigationProp<any>;
route: RouteProp<{Example: {title: string}}, 'Example'>;
};
export default class Example extends Component<Props> {
constructor(props: Props) {
super(props);
this.props.navigation.setParams({title: 'title'});
}
componentDidUpdate() {
this.props.navigation.setOptions({title: this.props.route.params.title});
}
render() {
return (
<View style={styles.container}>
<Text style={styles.textStyle}>Use component did update :)</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
padding: 30,
},
textStyle: {
color: 'black',
fontSize: 20,
fontWeight: 'bold',
},
});

How to include styles in React create portal

I have ViewAllGraphs class:
import '../styles/Graph.css'
export class ViewAllGraphs extends React.Component {
constructor(props) {
super(props);
this.state = {
showWindowPortal: false,
}
And render method:
return (
<div>
{
this.state.showWindowPortal && (
<Graph closeWindowPortal={this.closeWindowPortal} >
<h1>Id Π³Ρ€Π°Ρ„ΠΈΠΊΠ° : {this.state.currentId}</h1>
<h1>НазваниС Π³Ρ€Π°Ρ„ΠΈΠΊΠ° : {this.state.currentTitle}</h1>
<img o src={`data:image/png;base64,${this.state.currentImage}`} />
<h1>Π”Π°Π½Π½Ρ‹Π΅ Π³Ρ€Π°Ρ„ΠΈΠΊΠ° : {this.state.currentData}</h1>
<button className="graph-button-close" onClick={() => this.closeWindowPortal()} >
Π—Π°ΠΊΡ€Ρ‹Ρ‚ΡŒ Π³Ρ€Π°Ρ„ΠΈΠΊ
</button>
</Graph>
)
}
</div>
My CSS file is located in ../styles/Graph.css
I want to style my graph component, for example, the button. This is code of this component:
import React from "react";
import ReactDOM from 'react-dom'
import '../styles/Graph.css'
class Graph extends React.Component {
constructor(props) {
super(props);
this.state = {
id: 0,
}
this.containerEl = null;
this.externalWindow = null;
}
componentDidMount() {
this.externalWindow = window.open('', '');
this.containerEl = this.externalWindow.document.createElement('div');
this.externalWindow.document.body.appendChild(this.containerEl);
this.externalWindow.document.title = 'A React portal window';
this.externalWindow.addEventListener('beforeunload', () => {
this.props.closeWindowPortal();
});
this.shouldComponentUpdate();
this.setState({
id: 1,
})
}
shouldComponentUpdate() {
return true;
}
componentWillUnmount() {
this.externalWindow.close();
}
render() {
if (!this.containerEl) {
return null;
}
else
return ReactDOM.createPortal(this.props.children, this.containerEl);
}
};
export default Graph
I am trying to include the CSS file and apply className="graph-button-close" in render method to my button, but it's not working. Why can't I import the CSS file to graph class?
You can try these code:
this.containerEl = this.externalWindow.document.createElement('div');
this.containerEl.className = 'image';
this.containerEl.style.backgroundImage = 'url(http://via.placeholder.com/350x150)';
// add the image to its container; add both to the body
// this.containerEl.appendChild(img);
this.externalWindow.document.body.appendChild(this.containerEl);
Or for current elem you can use inline styles in parent component
let styleConfig = { backgroundColor: 'blue' }
In render method:
<p style={styleConfig}>Π”Π°Π½Π½Ρ‹Π΅ Π³Ρ€Π°Ρ„ΠΈΠΊΠ° : {this.state.currentData}</p>
To style a component functionally, and I hope this works for Class Components as well, is that for the styling part of the top of the file, I import the style as a component, something like this,
import componentStyling from '../styles/Graphs.css`;
A bit of advice is that 99% of the time, I want a style to only apply to that component. It's tremendously hard to think of unique class names every single time I make to add styling to a component, so I rename my CSS files with the following format, classComponentName.module.css, or classComponentName.module.scss, if you're using SCSS.
So, whatever the name of the component you're making is, whether it's functional or a class component, name your CSS files with respect to that and then suffix it with .module.css.
Now, the import looks something like this,
import componentStyling from `../styles/Graphs.module.css`;
Now, in the rendering part of the component, wherever I want to apply a class from Graphs.module.css to an HTML component in the component I have, I simply write,
<htmlElement className={componentStyling.classNameFromTheStylesFile}>
{/* some more JSX here */}
</htmlElement>
Where classNameFromTheStylesFile is a class name that exists within Graphs.module.css, which can be for example,
.classNameFromTheStylesFile {
background-color: blue;
};
I hope I got the question right.
Cheers!

Use hook in class component React

Hello I have checked the few articles on the subject, but I was not successful in doing the same.
I would like if possible an example if possible.
import React from 'react'
import { useInView } from 'react-intersection-observer'
const Component = () => {
const [ref, inView, entry] = useInView({
/* Optional options */
threshold: 0,
})
return (
<div ref={ref}>
<h2>{`Header inside viewport ${inView}.`}</h2>
</div>
)
}
it's ok
class Nameclasse extends Component
{
constructor(props)
{
super(props);
const [ref, inView, entry] = useInView({
/* Optional options */
threshold: 0,
})
}
render()
{
return (<div></div>);
}
}
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
See fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
In my opinion React Hook is a option to use states in situations where you won`t like to use (react) components. Therefore the syntax should look like a this:
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
const [ref, inView, entry]: useInView({
/* Optional options */
threshold: 0,
})
};
}
render() {
return (
<>
</>
);
}
}
I don`t if this is working (no time), but maybe its worth a try or some other more experienced coder could help you :)
source: https://reactjs.org/docs/hooks-state.html
State management with a Hook is exclusive to development by function, for any change of a state in a class you must go through the inherited function this.setState();
Function ex :
function Counter() {
const [count,setCount] = useInView(0)
return (<div> <button onclick={() => {setCount(count + 1)}}>Click me + 1</button> {count}</div>);
}

Implement shouldComponentUpdate with React hooks - Render child only once, but make DOM changes when props change

I have something working with a React.Component using shouldComponentUpdate, and want to convert it to use React Hooks, but I'm not sure it's even possible.
I have a child component that renders a very expensive ChartingLibrary canvas, so I only want to render the Child react component once.
The charting canvas content is dependent on props passed to the Child and certain apis on the ChartingLibrary have to be called with the props passed to the child.
So when the props passed to the child changes, I need to call apis on the Charting Library, but I don't want to refresh the Child component.
This is working with a React Class as follows:
const Parent = () => {
<Child/>
}
export class Child extends React.Component {
shouldComponentUpdate (nextProps, nextState) {
ChartingLibrary.init()
ChartingLibrary.doStuffWithProps(nextProps.data)
return false
}
}
React.memo is problematic:
The closest I can get to the React.Component version is with React.Memo, but I don't have access to the ChartingLibrary from inside the isSame function. React. The React.Component version gives me access to ChartingLibrary from inside the component whereas React.memo can only be done from outside the component.
const Parent = () => {
<Child/>
}
const Child = (props) => {
ChartingLibrary.init()
ChartingLibrary.doStuffWithProps(props)
}
const ChildMemo = React.memo(Child, function isSame (prevProps, props) {
ChartingLibrary.doStuffWithProps(props)
return true
})
Is there a better way? Is what I'm trying to do possible with hooks?
You are doing it the right way i guess. React.memo is the way you can achieve what you are looking for.
function MyComponent(props) {
/* render using props */
}
function areEqual(prevProps, nextProps) {
/*
return true if passing nextProps to render would return
the same result as passing prevProps to render,
otherwise return false
*/
}
export default React.memo(MyComponent, areEqual);
As said in the documentation:
Unlike the shouldComponentUpdate() method on class components, the
areEqual function returns true if the props are equal and false if the
props are not equal. This is the inverse from shouldComponentUpdate.
Hope this will help you.
Thank you #Muhammad Zeeshan, I needed that to only animate a text field (RN) when the props changed:
import React, { useEffect, useRef } from 'react';
import { Animated } from 'react-native';
const AnimatedView = props => {
const animatedOpacity = useRef(new Animated.Value(0)).current;
useEffect(() => {
Animated.sequence(
[
Animated.timing(animatedOpacity, {
toValue: 0,
duration: 500,
useNativeDriver: true
}),
Animated.timing(animatedOpacity, {
toValue: 1,
duration: 0,
useNativeDriver: true
})
],
{ useNativeDriver: true }
).start();
}, [props.children]);
return (
<Animated.Text
style={{
opacity: animatedOpacity
}}
>
{props.children}
</Animated.Text>
);
};
const comparator = (prevProps, nextProps) => {
if (prevProps.children !== nextProps.children) {
return true;
}
return false;
};
export default React.memo(AnimatedView, comparator);

Duplicating same helper functions over and over in D3 React Component

I am working on a d3 react component, and am running into this issue where I have to re-define my constants and helper functions over and over again. I have the following, general layout for my d3 component:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
chartType: 'A'
}
}
getHitData() {...}
drawChartA() {...}
drawChartB() {...}
drawChartC() {...}
drawChartD() {...}
drawChartE() {...}
toggleButton() {...}
componentDidMount() {
this.drawChartA()
}
componentDidUpdate() {
const { chartType } = this.state;
if(chartType == "A") {
this.drawChartA()
}
else if(..B) {...}
else if(..C) {...}
...
}
render() {
return (
<div>
<svg className='chart'>
<g className='chartA' />
<g className='chartB' />
<g className='chartC' />
<g className='chartD' />
</svg>
</div>
)
}
}
In my actual code, in each of my different drawChartA(), drawChartB(), etc. functions, I am finding myself having to redefine both constants (chartWidth, chartHeight, padding, margin), as well as certain important d3 helper functions (colorScales, xScale, yScale, radiusScale, etc.), and this doesn't feel right. In particular, I am breaking the DRY principle.
Should chartWidth / padding / etc. constants be defined in this.state? And what should I do with all of my helper d3 functions? I don't think these should be parameters to the drawChart() functions.
Any thoughts on this would be greatly appreciated, thanks!
Should chartWidth / padding / etc. constants be defined in this.state?
No, constants should never be part of the state. Only data that changes how your component is rendered or behaves when the data is changed should be part of the state.
You can store constants as class properties and initialize them in the constructor.
Similarly you can define helper functions on the class.
constructor(props) {
super(props);
this.state = {
chartType: 'A'
}
this.chartProperties = {
width: 25,
height: 30,
margin: 35
};
}
colorScales() { ... }
drawChartA() {
const colorScales = this.colorScales();
return <chart width={ this.chartProperties.width } />
}

Categories

Resources