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
Related
I am following a guide to upgrade to React 18. After completing the upgrade I am seeing errors on certain pages in my app.
ReactDOM.unstable_renderSubtreeIntoContainer() is no longer supported in React 18.
I am not using the unstable_renderSubtreeIntoContainer() function anywhere in my app, but when I look closer at what is causing these errors it seems to be caused my Bootstrap components.
Is there anyway to update this to remove the errors?
I ran into the same problem with react-bootstrap#v0.33.1 specifically when using OverlayTrigger component after upgrading to React 18. The warning message suggests to migrate to using portals. So I implemented a CustomOverlayTrigger component that leverages portals and referred to React's portal documentation to do so. Note that this solution is for Bootstrap 3 usage of OverlayTrigger (react-bootstrap v0.33.1). It seems later versions of react-bootstrap got rid of using ReactDOM.unstable_renderSubtreeIntoContainer. If you are not in a position to migrate to later versions (like I am), this solution will help for this use case. I have not check thoroughly if other components use the deprecated method, but the approach might be the same.
First of all, I copied the original source of the OverlayTrigger component code located here. You will need to clean up the imports and include into your code the utils function createChainedFunction located here.
I then created a portal wrapper based off React's documentation that looks like this:
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
const tooltipRoot = document.getElementById('tooltip-root');
class PortalWrapper extends React.Component {
constructor(props) {
super(props);
this.el = document.createElement('div');
}
componentDidMount() {
tooltipRoot.appendChild(this.el);
}
componentWillUnmount() {
tooltipRoot.removeChild(this.el);
}
render() {
// eslint-disable-next-line react/destructuring-assignment
return ReactDOM.createPortal(this.props.children, this.el);
}
}
PortalWrapper.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
};
export default PortalWrapper;
At the top, you can see the line const tooltipRoot = document.getElementById('tooltip-root');, I simply added in my index.html a div next to the react app's root div that will server as the anchor for my portal.
Then, back in the CustomOverlayTrigger component copied from react-bootstrap, I edited it in the follwing manner:
Remove all references to this._overlay and this._mountNode because the PortalWrapper now manages the mounting/unmounting. So I deleted componentDidMount(), componentDidUpdate(), componentWillUnmount() and renderOverlay()
I modified makeOverlay so that its result is wrapped by PortalWrapper so it became the following:
makeOverlay(overlay, props) {
return (
<PortalWrapper>
<Overlay
{...props}
show={this.state.show}
onHide={this.handleHide}
target={this}
>
{overlay}
</Overlay>
</PortalWrapper>
);
}
Finally, I changed the render method's return statement to become:
return (<>
{cloneElement(child, triggerProps)}
{this.makeOverlay(overlay, props)}
</>);
After this, I simply had to replace all my invocations to OverlayTrigger with CustomOverlayTrigger and I had the same result without the warning message.
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';.
I've got a (private) npm module that exports several React components. The module is bundled by Webpack and in the generated bundle a reference to one of the components (say Warning) looks like this:
t.d(n,"Warning",function(){return ge})
Then I've got a React project importing this module:
import { Warning } from 'my-custom-module';
...
render() {
return (
<Warning>Lorem ipsum</Warning>
);
}
This all works OK, but when I create a Jest snapshot of the component above, I expect the snapshot to look like
<Warning>Lorem ipsum</Warning>
but it looks like:
<ge>Lorem ipsum</ge>
For some reason Jest takes the minified identifier instead of the exported name of the component. How can I see the component name in the Jest snapshot? I'm unsure if I do need to adjust my Webpack config or the Jest setup...
Since you are referring the uglified version of the 'my-custom-module' it will try to render to the uglified names. However, I assume what you actually you need is to shallowly render your component.
You can use the Enzyme libraries's shallow renderer for this.
//MyAwesomeComponent.js
import { Warning } from 'my-custom-module';
export default class MyAwesomeComponent extends Component{
render(){
return (<Warning>Lorem ipsum</Warning>);
}
}
//MyAwesomeComponent.test.js
import { shallow } from 'enzyme';
import MyAwesomeComponent from './MyAwesomeComponent';
it('renders <MyAwesomeComponent />', () => {
const shallowMyComponent = shallow(<MyComponent />);
expect(shallowMyComponent).toMatchSnapshot()
});
This should show your snapshot as Warning without going a level deeper.
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
I'm creating a very simply input form in my react-redux app with redux-form. I'm following along the with the example of the redux-form page, but it's throwing me an error. The source of the error comes from trying to set the component prop to React.DOM.input. It throws this error:
TypeError: _react2.default.DOM is undefined
However, if I pass the string 'input' into the component prop, it works fine, and I can see the changed state in my redux dev tool. I'm just reaaaaally not sure where I got the idea to put it as a string and now I'm super curious 😂.
let SubsForm = ({ handleSubmit, availScripts }) => {
const subs = availScripts.map(script =>
[
<label htmlFor={script}>{script}</label>,
<Field key={script} component={React.DOM.input} type="checkbox" name={script} />,
<br />,
]
);
return [
<form>
{subs}
</form>
];
};
Thanks
There's a difference between import ReactDOM from "react-dom", and React.DOM.
The "react-dom" package is what you need to render React components into an HTML page.
Meanwhile, React.DOM was a set of factory functions for creating virtual DOM elements in render methods. It's been moved out into a separate react-dom-factories package, and is no longer part of the main React package as of React 16.
React.createElement() takes either a React component type or a string DOM HTML element name as its first argument, . The React.DOM factory functions wrapped up that process a bit. So, these are identical:
React.createElement("input", {name : "myInput"});
React.DOM.input({name : "myInput"})
Try importing the react component.
import React from "react";