Define component as constant - reactjs

Im following a React Native course and at some point the teacher defines a component as constnat using the following code:
const Comment = (props) =>
<Text>{props.text}</Text>
However I dont manage to make it work. I made a snack to just try the component individually and it doesnt work: https://snack.expo.io/S1eKSeV-7
I always get the error Invariant Violation: element type is invalid.
What Im doing wrong?

You are not exporting your component. That is why you get the error because Comment component is undefined.
import React from 'react'
import {Text} from 'react-native'
const Comment = (props) =>
<Text>{props.comment.text}</Text>
export default Comment

This is a functional component. There are two type of components in React: Functional and class components. If you don't need any state or don't use any lifecycle methods in your component you can and should use functional components.
Functional components
const SomeComponent = () => <div>Something</div>;
No need to use an explicit return here since arrow function do this for us if there is one single statement.
With regular function:
function SomeComponent() { return <div>Something</div> };
Class components
class SomeComponent extends React.Component {
state = { foo: "bar" };
someLifeCycleMethod() {
....
}
render() {
return( <div>Something</div>);
}
}
When you don't understand something always refer to official documentation.
The problem you are having is not directly related to component type. As suggested in another answer your component probably is not exported.

This will work:
const Comment = (props) => {
return (
<Text>{props.text}</Text>
);
};

Related

making a new react component want to add code not DOM

I'm relearning react, I've done tons and tons of angular I ran the following command :
generate-react component carousel
(I'm using generate-react-cli)
this works well and generates the following .tsx file (plus test, lazy-loading and style files, which I am omitting) :
import React from 'react';
import styles from './carousel.module.scss';
const carousel: React.FC = () => (
<div className={styles.carousel}>
carousel Component
</div>
);
export default carousel;
this loads fine in my app but now I want to add actual code, functions.
I can't seem to do this.
I've broken open this const like so :
const carousel: React.FC = () => {
constructor(props) {
super(props);
}
componentDidMount() {
}
return (
<div className={styles.carousel}>
carousel Component
</div>
);
}
I assume this is where the constructor and so on go,
however in this area the constructor name and ect. is not allowed.
so I tried changing the type to React.Component
however at that point I get an error directly on the const name stating :
TS2740: Type '() => Element' is missing the following properties from
type 'Component{}, {}, any>': context, setState, forceUpdate, render,
and 3 more.
I'm really shooting in the dark here and reacts docs are antithetical to examples. they refuse to help with any of this.
I want this newer, shorthand syntax but I also want to be able to use lifecycles and functions.
As it turns out the correc syntax for this is as follows :
class carousel extends React.Component {
componentDidMount() {
console.log('hello');
}
render() {
return (
<div className={styles.carousel}>
carousel Component
</div>
);
}
}

How to access props to external js file

The answers to this type of scenario I've seen all involved a class component.
I have a functional component in React.
const MyComponent = props => {
// all my code
// here I can execute props.firebase.someother stuff
}
As the above says I have a props.firebase which is linked to a firebase context. This allows me to call firebase. It works and it's all good.
To keep my code a little cleaner I'd like to do some of these calls in an external js file.
I'd like to do:
import { myMethod } from "./helpers/allcalls.js";
In my allcalls.js
export function setRecords(data) {
props.firebase.makecall.set(data)
}
const MyComponent = props => {
// all my code
// here I can execute props.firebase.someother stuff
setRecords(someDataFromState)
}
In the above props is undefined.
In a class I would bind that to (this) and then use this.props.firebase in the external js. I can't figure out how to do it in a functional component thou.
Any ideas?
Per this great help: #AlexW & #Claeusdev
Props is an object and can be passed to any outside method.
import { myMethod } from "./helpers/allcalls.js";
const MyComponent = props => {
// all my code
// here I can execute props.firebase.someother stuff
setRecords(props, someDataFromState)
}
In my allcalls.js
export function setRecords(data) {
props.firebase.makecall.set(data)
}
The above code is incomplete, it should be assumed props and all other import React, etc would be included.

How to use react-alert with React component that is defined as ES6 class

I am trying to use https://www.npmjs.com/package/react-alert in my project, but the examples are porvided for the React components that are declared as functions but my React components are declared as classes like:
class ConnectedOrderForm extends Component {
//const statusAlert = useAlert();
constructor(props) {
super(props);
}
render() {
return (
<div>Test</div>
)
}
}
const OrderForm = withRouter(connect(mapStateToProps, mapDispatchToProps)(ConnectedOrderForm));
export default OrderForm;
When I am trying to call useAlert().show('OK'); from class event, I am getting:
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:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
So, how can I use this react-alert hook from ES6 class component?
The solution was to use either export code:
const OrderForm = withRouter(connect(mapStateToProps, mapDispatchToProps)(ConnectedOrderForm));
export default withAlert()(OrderForm);
const OrderForm = withAlert()(withRouter(connect(mapStateToProps, mapDispatchToProps)(ConnectedOrderForm)));
export default OrderForm;
And call:
this.props.alert.show()
Based on the docs it would seem that you should not be using the useAlert hook but rather the withAlert HOC. Hooks can only be used in functional components, and since you want to use a class, you would need to the withAlert HOC.
Here is an example of that that would look like
import { withAlert } from 'react-alert'
class App extends React.Component {
render() {
const alert = this.props.alert;
return (
<button
onClick={() => {
alert.show('Oh look, an alert!')
}}
>
Show Alert
</button>
);
}
}
export default withAlert()(App)
Did you try this one?
import {alert} from 'react-alert';
alert.show('Some message', {
... options
})
UPD. Sorry, this is wrong answer, Please take a look here:
https://github.com/schiehll/react-alert/issues/116

How to export and import a function from a Class Component

I have a class component and inside i wanna define some functions to use them in other components.
I´m working with Framework7 and to use features like Dialogs it has to be a class component.
This is what i have tried so far:
class myComponent extends Component {
firstFunction = () => { // code };
secondFunction = () => { // code };
}
export { firstFunction, secondFunction }
import { firstFunction from './filename'}
I was hoping to build a component that holds these functions so i can use them wherever i import them but it seems like i´m on the wrong way here.
any help would be appreciated.
You can use Ref. (https://reactjs.org/docs/refs-and-the-dom.html)
When you are using your component, you can assign it a ref to have access to all its methods:
<MyComponent ref={ref => this.myComponentRef = ref} />
then:
this.myComponentRef.firstFunction()

Testing react components that have JSS injected styles with enzyme

I'm having a react component. Let's say Todo
import React, { Component } from 'react';
import injectSheet from 'react-jss';
class Todo extends Component {
// methods that incl. state manipulation
render() {
const { classes } = this.props;
return (
<div className={classes.container}>
<WhateverElse />
</div>
);
}
}
export default injectSheet(Todo);
I want to test it with enzyme. And there are two problems with it.
1. Access to the state
(and other component specific features)
When I shallow or mount that composer in the suite I can't get access to its state of course because it's not my component anymore but something new around it.
E.g. this code will give me an error:
it('should have state updated on handleAddTodo', () => {
const todo = shallow(<Todo />);
const length = todo.state('todos').length;
});
It says of course TypeError: Cannot read property 'length' of undefined because the state is not what I expect but this: { theme: {}, dynamicSheet: undefined }
This won't also give me access to props, refs etc.
2. Problems with theme provider
To provide some default colouring to the project like this:
import React, { Component } from 'react';
import Colors from './whatever/Colors';
class App extends Component {
render() {
return (
<ThemeProvider theme={Colors}>
<WhateverInside />
</ThemeProvider>
);
}
}
And of course when running tests it gives me an error [undefined] Please use ThemeProvider to be able to use WithTheme.
So my question is the following. Is there a way to solve this problem in “one single place”. How can I make enzyme agnostic of what is my component wrapped with?
If not, then how do I solve the problem if passing the ThemeProvider features down to the component that I'm testing?
And how can I access the state, ref, props and other things of the wrapped component?
Thank you!
here's what I'd do to test the component,
import React, { Component } from 'react';
import injectSheet from 'react-jss';
const styles = {};
class Todo extends Component {
// methods that incl. state manipulation
render() {
const { classes } = this.props;
return (
<div className={classes.container}>
<WhateverElse />
</div>
);
}
}
export { styles, Todo as TodoCmp }
export default injectSheet(styles)(Todo);
and in the test file, I'd add the following:
import { theme } from 'your-theme-source';
const mockReducer = (prev, curr) => Object.assign({}, prev, { [curr]: curr });
const coerceStyles = styles =>
typeof styles === 'function' ? styles(theme) : styles;
const mockClasses = styles =>
Object.keys(coerceStyles(styles)).reduce(mockReducer, {});
import {TodoCmp, styles} from 'your-js-file';
// then test as you'd normally.
it('should blah blah', () => {
const classes = mockClasses(styles);
const todo = shallow(<Todo classes={classes} />);
const length = todo.state('todos').length;
})
Please read more about it in the nordnet-ui-kit library specifically in the test directory. Here's a quick example
It is not related to JSS specifically. Any HOC wraps your component. Ideally you don't test any internals of a component directly.
Components public api is props, use them to render your component with a specific state and verify the rendered output with shallow renderer.
For some edge cases if first and preferred way is impossible, you can access the inner component directly and access whatever you need directly. You will have to mock the props the HOC would pass otherwise for you.
const StyledComponent = injectSheet(styles)(InnerComponent)
console.log(StyledComponent.InnerComponent)
If your component relies on theming, you have to provide a theme provider, always.

Resources