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.
Related
I'm trying to implement a static method to make my code cleaner. It has worked fine until I tried to do this:
// Auth.js
import {useDispatch} from 'react-redux';
import {signOut} from './redux_actions';
export class Auth {
static signOut = () => {
const dispatch = useDispatch();
dispatch(signOut())
}
}
// Menu.js
import {Auth} from '../../auth'
...
...
<MenuItem onClick={() => {Auth.signOut()}}><ExitToAppIcon className="icon"></ExitToAppIcon><span>log out</span></MenuItem>
However I get an error:
Invalid Hook call, You might have mismatching versions of React and React DOM.
You might be breaking the Rules of Hooks.
You might have more than one copy of React in the same app
I don't really know what I'm doing wrong. Probably i still don't really get the architecture. Thanks for your help!
EDIT:
according to the accepted answer, this worked
import { myStore } from './index'
export default class Auth {
static signOut = () => {
myStore.dispatch(signOut())
}
}
Here are the rules of React Hooks :
Call Hooks from React function components
Call Hooks from custom Hooks
It seems that your are calling the hook useDispatch from an external function (nor a function component neither a customHook), that's why you get this error.
You can call const dispatch = useDispatch(); dispatch(signOut()); inside your component or if you really want to keep the Auth class, you can call the dispatch function directly from the store (without using the hooks) like this :
import store from './path/to/your/store'
export class Auth {
static signOut = () => {
store.dispatch(signOut())
}
}
You are trying to use a react hook in a class. This is not possible.
You have to be in a functional component to use hooks.
If you need to use a class, you can connect your component with the connect() HOC.
You can't use useDispatch or any other hook in an event handler. Hooks can only be used in top level.
This should work:
export class Auth {
static useSignOut = () => {
const dispatch = useDispatch();
return () => dispatch(signOut())
}
}
// Menu.js
import {Auth} from '../../auth'
...
...
const signOut = Auth.useSignOut(); // now `useDispatch` is called at top level
<MenuItem onClick={signOut}><ExitToAppIcon className="icon"></ExitToAppIcon><span>log out</span></MenuItem>
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()
I'm using react with react-redux and eslint. In my container, I import an action that will be bound to the component's props in mapDispatchToProps like so:
// simplified for brevity
import { getGames } from '../actions/game';
const mapDispatchToProps = dispatch => ({
getGames: () => dispatch(getGames())
});
class App extend React.Component {
// class members
}
export default App connect(mapDispatchToProps)(App);
I call getGames in componentDidMount:
componentDidMount () {
const { getGames } = this.props;
getGames().then(json => console.log(json));
}
Eslint insists that I use object destructuring to pull values from this.props in componentDidMount, which is fine.
The problem is, eslint also complains that getGames is already declared in the outer scope (the import statement) when I do use object destructuring.
I'd like to appese eslint in both cases, but can't think of how I'd use object destructing in both the import and the this.props destructure without causing a naming conflict.
Any ideas are much appreciated!
// simplified for brevity
import { getGames } from '../actions/game';
you can use alias for it.
import { getGames as getGames1 } from '../actions/game';
and use alias instead.
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>
);
};
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.