How do I include a namespace with a react tsx import? - reactjs

When I try to import the component 'deleteButton', the compiler claims the class does not exist.
I have tried using an export default, and importing it under an alias.
import React from 'react';
import deleteButton from './Components/deleteButton';
const App: React.FC = () => {
return (
<deleteButton/>
);
}
export default App;
import React from 'react';
import { confirmAlert } from 'react-confirm-alert';
import 'react-confirm-alert/src/react-confirm-alert.css';
export default class deleteButton extends React.Component {
submit = () => {
confirmAlert({
title: 'Confirm to delete',
message: 'Are you sure to delete this file?.',
buttons: [
{
label: 'Yes',
onClick: () => alert('File deleted')
},
{
label: 'No',
onClick: () => alert('Canceled')
}
]
});
};
render() {
return (<div className='container'>
<button onClick={this.submit}>Delete</button>
</div>);
}
}
The expected output should be an HTML Element.
The compiler claims:
Property 'deleteButton' does not exist on type 'JSX.IntrinsicElements'. TS2339

You need to write JSX-Elements upper-case so that react can distinguish between custom elements and build-in ones like span or div. Docs
If you write it lower case, it will look for a native element, which does not exist. So change the name to be upper-case and it will work:
import DeleteButton from './Components/deleteButton';
Hope this helps. Happy coding.

Related

when I use jest to test react component it throws "Invariant Violation:Element type is invalid: expected a string (for built-in components)"

my code is
import React, {Fragment} from 'react'
import ReactTooltip from 'react-tooltip'
import PropTypes from 'prop-types'
class Tooltip extends React.Component {
childRef = React.createRef();
render() {
const props = this.props;
const child = React.Children.only(props.children);
const trigger = React.cloneElement(
child,
{ref: this.childRef, 'data-tip': this.props.title}
)
if (!props.title) {
return trigger
}
return (
<Fragment>
{trigger}
<ReactTooltip place={props.placement} effect="solid"/>
</Fragment>
)
}
}
Tooltip.propTypes = {
title: PropTypes.string,
children: PropTypes.element.isRequired,
placement: PropTypes.string,
}
Tooltip.defaultProps = {
placement: 'bottom',
}
export default Tooltip
and my test is :
import React from 'react'
import {mount} from "enzyme"
import {Tooltip} from "../../../../../main/js/app/components/ui/Tooltip"
describe('Tooltip', () => {
let props ,tooltip
beforeEach(() => {
props = {
title: 'test title',
placement: 'bottom',
children: <div/>
}
tooltip= mount(<Tooltip {...props}/>)
})
it('should render', () => {
// jest.fn(React.Children.only(props.children))
// const child = React.Children.only(props.children);
// const reactTooltip =tooltip.find(ReactTooltip)
// expect(reactTooltip).toContain("bottom")
})
})
when I run the test,it throws error:
Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
If you are trying to import the named export (Tooltip from export default Tooltip), this should fix it:
import Tooltip from "../../../../../main/js/app/components/ui/Tooltip"
However, if you only with to import the Tooltip class, you will need to export the class component itself,
export class Tooltip extends React.Component {
// the rest
}
Followed by importing only the class component, rather than the default export.
import { Tooltip } from "../../../../../main/js/app/components/ui/Tooltip"

TS2604: When importing 'material-ui' button from one package to another

My team is implementing a new front-end for our application and has decided to switch from standard react to typescript. I am fairly new at developing and have been stuck on this issue for several days. Essentially we have two repositories, one that holds our components, and the other that ties them together for a front-end application. We connect these via lerna/yarn link.
The problem I face lies when importing our version of the material-ui button component from the other library and also applies to several other components. When doing so, it fails to compile.
The code in the component library compiles correctly. However we receive this error only when importing it to the other application.
I have tried several things to try to solve this issue, first modifying the Button.d.ts file within our dist/ folder within the component changing the type of ReactComponent exported, changing interface to class, etc. Second, modifying the tsconfig.json to include adjusting multiple options available via the documents, changing the "types" path, etc.
Here are what I believe to be the relevant files within the component library:
Button.d.ts:
import React from 'react';
import { ButtonProps as MuiButtonProps } from '#material-ui/core/Button';
export interface ButtonProps extends MuiButtonProps {
defaultMargin?: boolean;
classes: {
root: string;
};
}
declare const _default: React.ComponentType<Pick<React.PropsWithChildren<ButtonProps>, "disabled" || "mini" & import("#material-ui/core/styles").StyledComponentProps<"root">>;
export default _default;
Button.tsx:
import React, { Fragment } from 'react';
import clsx from 'clsx';
import { withStyles, createStyles } from '#material-ui/core/styles';
import { default as MuiButton, ButtonProps as MuiButtonProps } from '#material-ui/core/Button';
export interface ButtonProps extends MuiButtonProps {
defaultMargin?: boolean,
classes: {
root: string
}
};
const styles = () => createStyles({
root: {
margin: '1.5em'
}
});
const Button: React.SFC<ButtonProps> = (props: ButtonProps) => {
return (
<Fragment>
<MuiButton
className={clsx({
[props.classes!.root]: props.classes!.root
})} {...props}>
</MuiButton>
</Fragment>
)
};
Button.defaultProps = {
variant: 'contained',
color: 'primary',
size: 'medium',
disabled: false
};
export default withStyles(styles)(Button);
tsconfig.json:
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": { "*": ["types/*"] },
"outDir": "types"
},
"declaration": true,
"include": ["src", "types"],
"types": "dist/core/src/index.d.ts",
"main": "dist/index.js",
"files": [
"dist/core/src/index.d.ts"
]
}
And here within the main application library
App.tsx:
import React, { Component } from 'react';
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { Button } from '#our-company/our-component-library-core'
import { Grid } from '#our-company/our-component-library-layout'
import { get } from 'lodash'
import './App.css';
import authenticationActions from '../reducers/authentication/actions'
import userActions from '../reducers/user/actions'
type Props = {
authDispatch: {
login: (args: any) => any,
logout: () => any
},
userDispatch: {
fetchUser: () => any
},
user: object
}
type State = {
count: number;
}
class App extends Component<Props, State> {
componentDidMount () {
this.props.authDispatch.login({email: 'email#email.com', password: '123456789'})
this.props.userDispatch.fetchUser()
this.props.authDispatch.logout()
}
render() {
const { user } = this.props
return (
<div className="App">
<header className="App-header">
<Grid container>
<Button variant="contained" color="primary">HELLO </Button>
<h1>{ get(user, ['user', 'attributes', 'email']) }</h1>
</Grid>
</header>
</div>
);
}
}
function mapStateToProps (state: any) {
const {
user
} = state
return {
user
}
}
function mapDispatchToProps (dispatch: any) {
return {
userDispatch: bindActionCreators(userActions, dispatch),
authDispatch: bindActionCreators(authenticationActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
I expect the code to compile, however it fails with a
ERROR in [at-loader] ./src/app/App.tsx:37:12
TS2604: JSX element type 'Button' does not have any construct or call signatures.
You are exporting a button component you have created:
const Button
The export is a default export:
export default withStyles(styles)(Button);
Whatever is the result of withStyles call, is not something that can be used as a JSX element.

Render HOC(Component) without changing Component Name in JSX

I have two HOCs that add context to a component like so :
const withContextOne = Component => class extends React.Component {
render() {
return (
<ContextOne.Consumer>
{context => <Component {...this.props} one={context} /> }
</ContextOne.Consumer>
);
}
};
export default withContextOne;
Desired Result
I just want an syntactically concise way to wrap a component with this HOC so that it doesn't impact my JSX structure too much.
What I have tried
Exporting a component with the HOC attached export default withContextOne(withContextTwo(MyComponent)) This way is the most concise, but unfortunately it breaks my unit tests.
Trying to evaluate the HOC from within JSX like :
{ withContextOne(withContextTwo(<Component />)) }
This throws me an error saying
Functions are not valid as a React child. This may happen if you return a Component instead of < Component /> from render.
Creating a variable to store the HOC component in before rendering :
const HOC = withContextOne(Component)
Then simply rendering with <HOC {...props}/> etc. I don't like this method as it changes the name of the component within my JSX
You can set the displayName before returning the wrapped component.
const withContextOne = Component => {
class WithContextOneHOC extends React.Component {
render() {
return (
<ContextOne.Consumer>
{context => <Component {...this.props} one={context} /> }
</ContextOne.Consumer>
);
}
}
WithContextOneHOC.displayName = `WithContextOneHOC(${Component.displayName})`;
return WithContextOneHOC;
};
This will put <WithContextOneHOC(YourComponentHere)> in your React tree instead of just the generic React <Component> element.
You can use decorators to ease the syntactic pain of chained HOCs. I forget which specific babel plugin you need, it might (still) be babel-plugin-transform-decorators-legacy or could be babel-plugin-transform-decorators, depending on your version of babel.
For example:
import React, { Component } from 'react';
import { withRouter } from 'react-router';
import { injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import { resizeOnScroll } from './Resize';
#withRouter
#resizeOnScroll
#injectIntl
#connect(s => s, (dispatch) => ({ dispatch }))
export default class FooBar extends Component {
handleOnClick = () => {
this.props.dispatch({ type: 'LOGIN' }).then(() => {
this.props.history.push('/login');
});
}
render() {
return <button onClick={}>
{this.props.formatMessage({ id: 'some-translation' })}
</button>
}
}
However, the caveat with decorators is that testing becomes a pain. You can't use decorators with const, so if you want to export a "clean" undecorated class you're out of luck. This is what I usually do now, purely for the sake of testing:
import React, { Component } from 'react';
import { withRouter } from 'react-router';
import { injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import { resizeOnScroll } from './Resize';
export class FooBarUndecorated extends Component {
handleOnClick = () => {
this.props.dispatch({ type: 'LOGIN' }).then(() => {
this.props.history.push('/login');
});
}
render() {
return <button onClick={}>
{this.props.formatMessage({ id: 'some-translation' })}
</button>
}
}
export default withRouter(
resizeOnScroll(
injectIntl(
connect(s => s, ({ dispatch }) => ({ dispatch }))(
FooBarUndecorated
)
)
)
);
// somewhere in my app
import FooBar from './FooBar';
// in a test so I don't have to use .dive().dive().dive().dive()
import { FooBarUndecorated } from 'src/components/FooBar';

react-select component, not rendering

react: ^15.4.2,
react-select: ^1.0.0-rc.10,
Example.tsx
import * as React from 'react';
import Select from 'react-select';
// Be sure to include styles at some point, probably during your bootstrapping
import 'react-select/dist/react-select.css';
var Select = require('react-select');
var options = [
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' }
];
function logChange(val) {
console.log("Selected: " + JSON.stringify(val));
}
export class Example extends React.Component<any, any> {
render() {
return (
<div>
<Select name="form-field-name" value="one" options={options} onChange={logChange}/>
</div>
);
}
}
No errors reported at compile time.
Get an error message when attempting to render it
React.createElement: type is invalid -- expected a string (for
built-in components) or a class/function (for composite components)
but got: object. Check the render method of Example.
in Example
Being this is my first react project I have no idea how to debug this. I do not see anything wrong with this code.
Here is my render out of main.tsx
(() => {
const container = document.querySelector('#container');
render( <Example />, container);
})();
Well, from the example above which is copy-pasted from react-select docs seems that everything is alright. The error says that you try to render something that is not being able to render (here it says it's some Object).
My bet is this line causes the error:
import Select from 'react-select';
are you sure you properly installed this package?
Try to usw curly brackets arround Select in your import statement:
import {Select} from...
If there are no "default" export defined, you have to use those curly bracets to define the component you want to use.
import * as React from 'react';
import Select from 'react-select';
// Be sure to include styles at some point, probably during your bootstrapping
import 'react-select/dist/react-select.css';
export class Example extends React.Component<any, any> {
var options = [
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' }
];
function logChange(val) {
console.log("Selected: " + JSON.stringify(val));
}
render() {
return (
<div>
<Select name="form-field-name" value="one" options={options} onChange={logChange}/>
</div>
);
}
}
import React, { Component } from 'react';
import Select from 'react-select';
class App extends Component {
state = {options: [
{
value: '1', label: 'Option 1',
},
{
value: '2', label: 'Option 2',
}
]}
render(){
return (
<div>
<Select
className={"select-item"}
name="option name"
onChange={this.changeHandler}
options={this.state.options}
/>
</div>
)
}
}
Quick answer, this should work:
Demo: https://codesandbox.io/s/stupefied-vaughan-z4mkv?file=/src/Example.tsx
import * as React from "react";
import Select from "react-select";
// Be sure to include styles at some point, probably during your bootstrapping
import "react-select/dist/react-select.css";
var options = [
{ value: "one", label: "One" },
{ value: "two", label: "Two" }
];
function logChange(val) {
console.log("Selected: " + JSON.stringify(val));
}
export default class Example extends React.Component<any, any> {
render() {
return (
<div>
<Select
name="form-field-name"
value="one"
options={options}
onChange={logChange}
/>
</div>
);
}
}
Reason for error:
Either use export default class Example extends React.Component<any, any> {, or in whichever file you are importing and using <Example />, import it as import { Example } from './path/to/file'. Not using the default export specifier or named import in the importing file is causing the error. Read imports / exports in js
Things to do:
Remove var Select = require('react-select');. This is the same as import Select from 'react-select';, just in a different import format (read about ESM and CommonJS to learn more). We should avoid importing components
Use import React from 'react' instead.

RelayContainer: `Relay` was rendered with invalid Relay context `undefined`

i'm using ReactJS, Relay Framework and GrapthQL. This is the layout component where i use relay to get data:
import React, { PropTypes } from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Header from '../Header';
import Footer from '../Footer';
import Sidebar from '../Sidebar';
import Relay from 'react-relay';
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();
class Layout extends React.Component{
render(){
const {children} = this.props;
var communityList = this.props.communityList;
return (
<MuiThemeProvider>
<div>
<Header/>
<Sidebar/>
{React.Children.only(children)}
<Footer />
</div>
</MuiThemeProvider>
)
}
}
Layout.propTypes = {
children: PropTypes.element.isRequired,
};
var RelayLayout = Relay.createContainer(Layout, {
fragments: {
communityList: () => Relay.QL`
fragment on Layout {
user(id: 11) {
connections{
community{
name
}
}
}
}
`,
},
});
export default RelayLayout;
The problem is: when i run the page, it show the error message:
Invariant Violation RelayContainer: Relay(Layout) was rendered with invalid Relay context undefined. Make sure the relay property on
the React context conforms to the RelayEnvironment interface.
The query using GrapthQL return valid data so i don't think problem is the query
I had the same problem when I was running my tests. You need to wrap the Relay container with a Relay.RootContainer or Relay.Renderer component. Like this:
const ViewerQuery = { viewer: () => Relay.QL`query { viewer }` };
const queryConfig = {
queries: ViewerQuery,
params: {},
name: 'User'
};
<Relay.Renderer
Container={User}
queryConfig={ViewerQuery}
environment={Relay.Store}
render={({done, error, props, retry, stale}) => {}} />

Resources