ReactJS export const and component from one module - javascript

I have two modules that I want to share a const array. One of these modules includes both the const array and a component, whilst the other module only includes a component.
This is what I have in module "A".
export const ORDER_COLUMNS = [
{ name: 'orderNumber', title: 'Order', width: '10%', type: 'string' },
{ name: 'orderType', title: 'Type', width: '10%', type: 'string' }
];
class OrderGridControl extends React.Component {
constructor(props) {
super(props);
this.state = {
orderColumns: ORDER_COLUMNS
};
}
...
}
export default OrderGridControl;
And in module "B".
import {OrderGridControl, ORDER_COLUMNS} from 'component/order-grid-control';
class OrderQueryPage extends React.Component {
constructor(props) {
super(props);
this.state = {
orderColumns: ORDER_COLUMNS
};
console.info(this.state.orderColumns);
}
...
render() {
return (
<div>
<PropertyGrid gridSetup={this.state.orderColumns} />
</div>
);
}
}
When I run this I get the following error. invariant.js:39 Uncaught Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. Check the render method of 'moduleB'.
However, the console.info(this.state.orderColumns) line logs all the column objects I expect.
Interestingly, if I copy the array into module "B" and assign the columns in the constructor exactly the same way it seems to work. It only seems to be an issue when I'm importing from the other module.

You've got it almost right-- you're exporting a default export (OrderGridControl) and a named export (ORDER_COLUMNS).
However, in B.js, you're trying to import two named exports.
Modify your import to look like this:
import OrderGridControl, { ORDER_COLUMNS } from 'component/order-grid-control';
The advantage of having a default export is that you don't have to match its name exactly when importing it, so you could do something like
import GridControl, { ORDER_COLUMNS } from 'component/order-grid-control';

Related

Getting Invariant Violation while making routes in react-native-tab-view

Current behaviour
While using react-native-tab-view v1.0.0, getting error:
Invariant Violation: 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.
Check the render method of `SceneComponent`.
This error is located at:
in SceneComponent (at SceneMap.js:16)
in RCTView (at View.js:43)
in AndroidViewPager (at ViewPagerAndroid.android.js:247)
in ViewPagerAndroid (at PagerAndroid.js:154)
in PagerAndroid (at TabView.js:59)
in RCTView (at View.js:43)
in RCTView (at View.js:43)
in TabView (at UnderlineTabbar.js:76)
Expected behaviour
Should not throw error and run.
Code sample as below
/* #flow */
import * as React from 'react';
import { StyleSheet, Dimensions, View } from 'react-native';
import {
TabView,
TabBar,
SceneMap,
type Route,
type NavigationState,
} from 'react-native-tab-view';
import LinearGradient from 'react-native-linear-gradient';
import CategoryPage from './CategoryPage';
import GestureRecognizer, {swipeDirections} from 'react-native-swipe-gestures';
import ButtonWithIcon from '../../components/ButtonWithIcon';
type State = NavigationState<
Route<{
key: string,
title: string,
}>
>;
const initialLayout = {
height: 0,
width: Dimensions.get('window').width,
};
export default class UnderlineTabbar extends React.Component<*, State> {
constructor(props) {
super(props);
this.state = {
index: 0,
routes: [],
scenes: {}
};
props.categories.forEach(category => {
this.state.routes.push({ key: category.description, title: category.name });
});
let scenes = {};
props.categories.forEach(category => {
if(category.assets.length > 0) {
const FirstRoute = () => (
<View style={[styles.container, { backgroundColor: '#ff4081' }]} />
);
scenes[category.description] = FirstRoute;
}
});
this.state.scenes = scenes;
}
_handleIndexChange = index =>
this.setState({
index,
});
_renderTabBar = props => (
<TabBar
{...props}
scrollEnabled
indicatorStyle={styles.indicator}
style={styles.tabbar}
tabStyle={styles.tab}
labelStyle={styles.label}
/>
);
render() {
const config = {
velocityThreshold: 0.1,
directionalOffsetThreshold: 800
};
return (
<TabView
style={[styles.container, this.props.style]}
navigationState={this.state}
renderScene={SceneMap(this.state.scenes)}
renderTabBar={this._renderTabBar}
onIndexChange={this._handleIndexChange}
initialLayout={initialLayout}
/>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
tabbar: {
backgroundColor: '#3f51b5',
},
tab: {
width: 120,
},
indicator: {
backgroundColor: '#ffeb3b',
},
label: {
color: '#fff',
fontWeight: '400',
},
});
Your code sample is incomplete, so it's hard to say, but the error suggests that you may be importing the TabView or View components incorrectly (possibly referring to a default export instead of a named export, or vice versa). I'll update this answer with something more helpful if you can provide the full code sample for that file (don't cut off the imports).
Invariant Violation: 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.

React Proptypes

React provides proptypes for type checking as the following code block demonstrates:
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
But I can do the following as well for the 'name' proptype:
Greeting.propTypes = {
name: String
};
In the later case i don't need to include the 'prop-types' module. Which one is the recommended approach?
The first way is the recommended way.
When you do
Greeting.propTypes = {
name: String
};
you are defining a javascript string field inside your proptypes object. Also, you will not be able to make the prop a required prop by using the above.
By using this
Greeting.propTypes = {
name: Proptypes.string.isRequired
};
you can make the proptype required and show a console warning if it is not supplied.

TypeScript failing on React typing

I'm sure there's something stupid that I'm missing, but I can't get my TypeScript compiler to compile a fairly simply React component. I'm using a .tsx file extension for my file which TypeScript should be able to handle via my webpack config. I get the following error: ERROR in ./src/App.tsx
(36,16): error TS2339: Property 'todos' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<ToDosList> & Readonly<{ children?: ReactNode; }> &...'.
Below is my code. I've tried both implicitly setting the state for the component (meaning without setting state: App.State) and explicitly giving state a type of App.State, but neither seem to work.
import * as React from 'react';
import ToDosList from './components/todos_list';
const todos = [
{
task: 'Make React tutorial',
is_completed: false
},
{
task: 'Eat Dinner',
is_completed: true
}
];
namespace App {
export interface Props {
}
export interface State {
todos: any
}
}
export default class App extends React.Component<App.Props, App.State> {
constructor(props) {
super(props);
this.state = { todos: todos };
}
render() {
return (
<div>
<h1>React ToDos App</h1>
<ToDosList todos={this.state.todos} />
</div>
);
}
}

Ant Design TextArea not rendering

Following is a form that I am trying to create through ant.design:
import { createElement as ce, Component } from 'react';
import { Form, Icon, Input, Button } from 'antd';
const FormItem = Form.Item;
const { TextArea } = Input;
class CommentForm extends Component {
render() {
return (
ce(Form, { layout: 'inline' },
ce(FormItem, {},
ce(TextArea, {}),
ce(Button, {
htmlType: 'submit',
type: 'primary',
}, 'Post'),
)
)
);
}
}
const CommentBubble = Form.create()(CommentForm);
export default CommentBubble;
I keep getting the following error when I try to use the TextArea:
Uncaught (in promise) Error: 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. Check the render method of CommentForm.
But I don't get the error if I render an Input instead of the TextArea.
Ant Design documentation.

How to properly use interfaces in Typescript

I came across a problem concerning interfaces and Typescript. The following example:
import * as React from "react";
/*
* An interface used to describe the properties of the react component.
*/
interface IUnsafeComponentProps {
component: IUnsafeComponent //& typeof React.Component;
}
/*
* An interface used to describe every component that is allowed to be rendered.
* It needs to define a property called "componentName".
*/
export interface IUnsafeComponent {
componentName: string;
componentStyles?: {};
}
/*
* The React component itself used to render the unsafe component.
*/
export class UnsafeComponent extends React.Component<IUnsafeComponentProps, any> implements IUnsafeComponent {
public componentName: string;
constructor(props: IUnsafeComponentProps) {
super(props);
this.componentName = "UnsafeComponent";
}
public render(): JSX.Element {
return <this.props.component/>;
}
}
The reason for such a wrapper is to allow to render third party code within my application. If I now try to use the component:
let content = <UnsafeComponent component={UnsafeComponent}/>;
ReactDOM.render(content, document.getElementById("root"));
I get the following error message:
Type 'typeof UnsafeComponent' is not assignable to type 'IUnsafeComponent'.
[0] Property 'componentName' is missing in type 'typeof UnsafeComponent'.
I have really no idea why my ddeclaraion is wrong. I am quite new to Typescript/Javascript. Maybe I am getting something very basic wrong here.
This declaration says you want an instance of IUnsafeComponent:
interface IUnsafeComponentProps {
component: IUnsafeComponent //& typeof React.Component;
}
Here, you passed the constructor function for UnsafeComponent:
<UnsafeComponent component={UnsafeComponent}/>;
What you probably wanted was this, which says that you want some constructor function that produces an IUnsafeComponent:
interface IUnsafeComponentProps {
component: new(...args: any[]) => IUnsafeComponent;
}
See also What does the error "JSX element type '...' does not have any construct or call signatures" mean? which talks about how JSX component references are to class constructors, not class instances.

Categories