Custom webcomponent from library in React - reactjs

I have a React application which should use the following library:
MICO-grapheditor
And I want to write this code:
render() {
var webgraph = require("#ustutt/grapheditor-webcomponent");
GraphEditor.
return (
<network-graph classes="red blue" mode="layout" zoom="both">
<style slot="style">
svg {width:100%; height: 100%}
</style>
<svg slot="graph"></svg>
</network-graph>
)
}}
But I get the following:
TS2339: Property 'network-graph' does not exist on type 'JSX.IntrinsicElements'.
How can I resolve this error?

At least the expression
var webgraph = require("#ustutt/grapheditor-webcomponent");
should come up before the rendering. Also, doing CSS in HTML and Node.js/React is not pretty much the same. Or is it?

React is likely assuming that network-graph is a React component, thus it expects that the attributes you are using (mode and zoom) are defined in a React component. Also React uses className instead of classes.
When you write between <network-graph> tags this content is considered as a group of child nodes that can be used by the network-graph component in the following way:
import React, { Component } from "react";
class NetworkGraph extends Component {
render() {
const {mode, zoom, children} = this.props;
return (
<>{children}</>
); // children would contain the <svg>
}
}
When you require MICO-grapheditor, you are not importing a React component, but a web component instead, even though React tries to interpret it...
Also, avoid shoving in <style> tags in the render's return. CSS styles in React may be imported to components like so import './my-styles.css';.

Related

How to wrap ALL components of react in a HOC?

ReactJS is a great library, However, it misses some features which I found in Vue and Angular. These features can be implemented of course in React, however, they require extra code to be written.
Every react component, or every JSX element I should say has the following properties shared, which are given by React to us to consume:
ref
key
I wanted to add extra props:
renderIf
fallback
These props help in a way I can't describe when it comes to conditional rendering and filtering the views based on the logged-in user permissions and roles (and other conditional rendering use cases, of course).
In react, if we wanted to apply these props to our components, we would use a HOC as follows:
// 🍎 Disclaimer: you don't have to understand any of the code written bellow, the general idea is that this is a HOC.
import React from 'react'
import getVal from './getVal'
export default function EnhancedComponent(OriginalComponent) {
return ({ renderIf: renderIf_ = true, override: override_, fallback: fallback_ = undefined, ...props }) => {
const renderIf = getVal(renderIf_)
const override = getVal(override_)
const fallback = getVal(fallback_)
const consumersComponent = <OriginalComponent {...props} />
let render = fallback
if (renderIf) render = consumersComponent
if (override_ !== undefined) render = override
return render
}
}
Where every time you want to apply these props to your components, you would have to wrap every new component you create with EnhancedComponent as follows:
export default EnhancedComponent(function Sidenav(){
return <div> side nav </div>
})
Now, you can use your Sidenav component within your App component as follows:
import Sidenav from './Sidenav'
export default function App(){
return (
<div>
<Sidenav renderIf={(5 + 5 === 10)}/>
<div>etc</div>
</div>
)
}
This API is great, but it has a drawback, which is, every time you want to apply these cool props (renderIf and fallback) you'll have to repeat these steps:
import Enhanced component to your file.
wrap your export with Enhanced component.
What I am looking for, is a method, or a way to inherit, or to add some props to the original react component class, somehow?
In react class components, I can imagine doing this on the React.Component class which we used to extend from in the past
class Car extends React.Component{
constructor(){}
render(){
return <div>I miss you 🌹</div>
}
}
But in react functional component, how can we do that?
I want to apply these props by default everytime I create a new component, without wrapping my components in a HOC everytime.
Does React have a way to do that? To change its defaults ?

How do I use getElementsByClassName when I'm using CSS modules in React.js?

I want to apply getElementsByClassName to a element with dynamic name assigned by CSS modules in React.js. For example, if I named a class as 'firstLink' using className={styles.firstLink} in a file named RegisterPage.js, the resulting name for the class is:
The __1Ozd bit is random. How can I apply getElementsByClassName in this situation ?
CSS modules provides key-value object which you can use in the code.
Key is class name defined by you, value is generated class name.
import React from 'react'
import style from './style.module.css'
export default function Component() {
React.useEffect(() => {
console.log(document.getElementsByClassName(style.firstLink))
}, [])
return <div className={style.firstLink} />
}
And I believe there can't be any reason to use vanilla js functions like getElementsByClassName, using state and in some cases using refs should cover all cases, example:
import React from 'react'
export default function Component() {
const ref = React.useRef()
React.useEffect(() => {
console.log(ref.current) // Will output dom element
}, [])
return <div ref={ref} />
}
After some thinking, perhaps there are old-school libraries which can accept root element only by class name.
In react, behaviors such as you wanted is termed Refs, see this.
If you are building functional component do this:
const {useRef} = React
const Component =>{
styelRef = useRef()
//refer to your anchor tag style here which should be called className
const styleFnc=()=>{
styleRef.current.className = "__1Ozd"
}
return(
<a ref={styleRef} href="...." className={`RegisterPage_firstLink${styelFnc}`}></a>
)
}

Invalid usage of this.props in react component

I'm getting the following error on webpack build and I don't understand why:
SyntaxError: this is a reserved word (11:5)
It occurs inside the Applicatons class at the code which says this.props.apps.map. Its trying to iterate through the passed apps property and create a JSX representation of Application components. I've included the Applications class as the first piece of code and the subsequent code shows how I instantiate the Applications component in a different class. I'm trying to access the props field inside the Applications class which extends the React Component
Here is the Applications class which I am clearly not using React props correctly:
import React from 'react';
import ReactDOM from 'react-dom';
import Application from './Application/Application';
import ErrorBoundary from '../ErrorBoundary/ErrorBoundary';
class Applications extends React.Component {
render(){
let applicationsList=null;
applicationsList = (
{this.props.apps.map((app,index)=>{
return <Application
name={app.name}
desc={app.desc}
changed={(event)=>this.props.changed(event,app.id)}
click={()=>this.props.clicked(index)}
key={app.id}
/>
})}
);
return (
{applicationsList}
)
}
}
And here is the code inside a different react component that instantiates the Applications component.
render(){
let applications=null;
applications = (
<div>
<Applications
apps={this.state.apps}
clicked={this.deleteApplicationHandler}
changed={this.nameChangedHandler}/>
</div>
);
return (<div>{applications}</div>);
}
I'm extremely new to react so i apologize if i missed anything if i did please let me know and ill update the question.
You're trying to use JSX templating syntax outside JSX. Curly brackets are interpreted as defining an object literal. Remove the extra brackets.
render(){
let applicationsList=null;
applicationsList = this.props.apps.map((app,index)=>{
return <Application
name={app.name}
desc={app.desc}
changed={(event)=>this.props.changed(event,app.id)}
click={()=>this.props.clicked(index)}
key={app.id}
/>
});
return applicationsList;
}

What's the difference between importing React's Fragment from React and React, { Fragment }?

What's the difference between import React from 'react' and import React { Fragment } from 'react' in context of <React.Fragment>, <Fragment> and <>?
I mean what happen when we import React and { Fragment } in the same line from a module?
Do we create instance of <Fragment> and this is just another few hundreds lines of code under the hood?
Or this is just normal and everybody can do that withouth performance downsides?
Official React blogpost mention that you can do this const Fragment = React.Fragment and they use in in their examples.
But why?
So assume you have an object.
let object = {
foo: '1',
bar: '2',
};
In order to use the value foo you can do the following
object.foo
let { foo } = object
These both are the same, the later mentioned way is called destructing which was introduced in javascript ES6 version.
Now coming to topic for
What's the difference between import React from 'react' and import React { Fragment } from 'react' in context of , and <>?
imagine React as object which has the following features e.g Fragment in this case. You can access it the following ways
1- First way
import React from 'react';
<React.Fragment></React.Fragment>
2-
import React, { Fragment } from 'react';
<Fragment></Fragment>
Now in the second way this is basically importing all React features and also destructing a feature from React which is Fragment. SO you don't have to write React.Fragment again and again.
3-
<></>
This is a babel feature, babel when compiling will convert <></> this into <React.Fragment></React.Fragment>
This is basically syntactic sugar:
import React, { Fragment } from 'react'
Will allow you to write the following:
class MyComponent extends React.Component {
render () {
return (
<Fragment>
<div className="fragment1">Fragment 1</div>
<div className="fragment2">Fragment 2</div>
<Fragment>
)
}
}
Instead of having to write explicitly React.Fragment. Note that you could also write the following if the only imports that you need are React.Component and React.Fragment:
import { Component, Fragment } from 'react'
class MyComponent extends Component {
render () {
return (
<Fragment>
<div className="fragment1">Fragment 1</div>
<div className="fragment2">Fragment 2</div>
<Fragment>
)
}
}
This may also become relevant when using module bundler such as Webpack, so your bundler will only import the required dependencies and it may result in a smaller bundle (AKA your app loads faster). Take a look at Tree Shaking for more details. This ultimately depends on how the imported package exports its modules, as mentioned in the reply above it may have no benefit for React - at the moment - but other libraries may leverage that mechanism. It is usually a good practice to try to keep your imports as strict minimum.
<></> syntax doesn’t support keys or attributes. When element is iterated it will throw the warning message 'Each child in a list should have a unique "key" prop'.
For Example :
{props.items.map(item => (
<>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</>
))}
See docs here https://reactjs.org/docs/fragments.html#keyed-fragments
Well there are no performance downsides, This is just have to do with extra markup. We do named export Fragment like Component that we usually do. As long as if you're concerned about performance, we're already importing from react which means complete react package Because there are not just Component, Fragment we need while exporting component in React Tree. There are under hood dependencies in react package we don't actually import but they are used in our component

React CSS Modules and testing the component

Inside my code I use babel-plugin-react-css-modules which is practically the same as react-css-modules
I have a code like this inside react component.
styleName is for CSS Modules and I define styles for them inside countdownForm.local.scss
className represent my Bootstrap classes
import './countdownForm.local.scss'
class CountdownForm extends Component {
...
render () {
return (
<div styleName="first" className="container">
...
</div>
)
}
}
To test this component inside my test I have to use ignore-styles package because JavaScript can't handle CSS syntax and when we run unit tests, the test will try to import the CSS file without Webpack which will result error.
import register from 'ignore-styles'
import React from 'react'
import test from 'tape'
import CountdownForm from 'CountdownForm'
register(undefined, () => ({styleName: 'fake_class_name'}))
test('CountdownForm => should exist', (t) => {
t.ok(CountdownForm)
t.end()
})
By doing this everything passes great and test works without problem but I always get this warning in the console
Warning: Unknown prop styleName on tag. Remove this prop from
the element.
It is not a problem of functionality because tests works but it is annoying to get this message every time I run tests. How to fix, get rid of it?
The warning is because you are not running the babel-plugin-react-css-modules compilation step before the test.
That works by replacing styleName prop with the computed CSS modules class names. Therefore styleName is never actually passed to the div in your real build (https://github.com/gajus/babel-plugin-react-css-modules#how-does-it-work). It would rewrite your component to something like...
class CountdownForm extends Component {
...
render () {
return (
<div className="container CountdownForm_first_123xyz">
...
</div>
)
}
}
In your test, without running the babel plugin first, you will successfully manage to ignore the CSS import via ignore-styles but the props replacement hasn't happened so you end up passing a styleName prop to the div, which is not a defined property for div component, so React will warn you
Best way to fix this would be to run a babel compilation step before the test, that way you can also test the real localised classnames assignment

Resources