Why cannot I not use connect in my React Native component? - javascript

I have a component that I need to call dispatch in (this.props.dispatch) but dispatch doesn't exist so I decided to add a connect to my component but I get an error when I do so. I am having trouble trying to figure out why adding a connect would throw an error when other components in my app also have a connect and don't act like this. If I remove the connect line then the error disappears. Does anyone know why I'm getting this error??
export default class ItemsInCartContent extends Component {
constructor(props) {
super(props);
this.state = {
active: null,
products: props.products,
ascending: true,
sortIcon: 'unsorted',
sortIconStyle: styles.sortIcon
};
this.props.dispatch(getOrderDetails(this.props.orderId));
}
render() {
const cartIcon = (<Icon name="shopping-cart" style={styles.cartIcon} />);
const sortIcon = (<Icon name={this.state.sortIcon} style={this.state.sortIconStyle} />);
return (
<View style={styles.itemsInCartContent}>
</View>
);
}
}
function mapStateToProps(state) {
const {products} = state;
return {
products
};
}
export default connect(mapStateToProps)(ItemsInCartContent);

The error is pretty clear if you read the log carefully:
... SyntaxError ... only one default export allowed per module ...
You got
export default class ItemsInCartContent extends Component {
and
export default connect(mapStateToProps)(ItemsInCartContent);
only one of those exports can be default.
I would advise to remove the export on ItemsInCartContent completely since the component is supposed to be used with connect, or, make it explicit:
export class ItemsInCartContent extends Component {

Related

TypeScript error Parameter 'props' implicitly has an 'any' type

I am testing out how to use Context in React but for some reason I cant run the app due the typescript error I get!
Code:
import React from 'react';
import './App.css';
class App extends React.Component {
render() {
return <Toolbar theme="dark" />;
}
}
function Toolbar(props) {
// The Toolbar component must take an extra "theme" prop
// and pass it to the ThemedButton. This can become painful
// if every single button in the app needs to know the theme
// because it would have to be passed through all components.
return (
<div>
<ThemedButton theme={props.theme} />
</div>
);
}
class ThemedButton extends React.Component {
render() {
return <button className={'btn btn-' + this.props.theme}></button>;
}
}
export default App;
Error I get:
C:/Users/as/Desktop/React - Mobx -Hooks/react-hooks-mobx/src/App.tsx
TypeScript error in C:/Users/iluli/Desktop/React - Mobx -Hooks/react-hooks-mobx/src/App.tsx(11,20):
Parameter 'props' implicitly has an 'any' type. TS7006
9 | }
10 |
> 11 | function Toolbar(props) {
Any idea how to fix this and explain the reason why it throws that error?
You just need to provide the Type for it:
import React from "react";
import "./App.css";
interface IToolbarProps {
theme: string;
}
class App extends React.Component {
render() {
return <Toolbar theme="dark" />;
}
}
// Here in the function
function Toolbar(props: IToolbarProps) {
// The Toolbar component must take an extra "theme" prop
// and pass it to the ThemedButton. This can become painful
// if every single button in the app needs to know the theme
// because it would have to be passed through all components.
return (
<div>
<ThemedButton theme={props.theme} />
</div>
);
}
// HERE as a generic
class ThemedButton extends React.Component<IToolbarProps> {
render() {
return <button className={"btn btn-" + this.props.theme}></button>;
}
}
export default App;

Can not access value of props

I was console logging the this.props from the render function-
And in the console I can see these-
However, when I try to access any one of them, say I wanted to access the store object, then if log like this console.log(this.props.store). Like this-
Then I get this-
I have no clue what so ever I am doing wrong. If anyone knows what I am doing wrong, please let me know. Any help is appreciated!
The whole code-
import * as React from 'react';
import { connect } from 'react-redux';
import mapStateToProps from './utilities/mapStateToProp';
//tslint:disable
class App extends React.Component {
constructor(props: any){
super(props);
}
public render() {
console.log(this.props);
return (
<div className="App">
<h1>React + TypeScript = {}</h1>
</div>
);
}
}
export default connect(mapStateToProps)(App);
Save them in your component state in your constructor and access them from there.
constructo(props){
super(props)
this.state = { store: props.store }
}
And in your render()
render(){
const { store } = this.state //use the store const to access to your value
console.log(store);
}
EDITED
About not using stateless component you should declare an interface in your component in order your component understand what kind of props has the state, review this link for more information Typescript and React
interface IMyComponentProps {
someDefaultValue: string
}
interface IMyComponentState {
store: any //dont know what type is your store.
}
class App extends React.Component<IMyComponentProps, IMyComponentState> {
// ...
}
To test a workaround to check if it works try this React.Component<{},any>

Rendering react component using typescript without passing in strongly typed props

I am having an issue trying to stronly type the props of a react component and only passing in 1 property to that component.
So take this for example:
I have this class App and it has a child component of class SideMenu. SideMenu has strongly type props like so:
class SideMenu extends Component<ISideMenu> {
render() {
return (
<div>
Test
</div>
);
}
}
const mapStateToProps = (state: IFileExplorerState) => {
return {
fileExplorerInfo: state.fileExplorer
};
};
export default connect<{}, {}, ISideMenu, IFileExplorerState>(mapStateToProps, {})(SideMenu);
and this is the ISideMenu interface I am using to strongly type the props:
export interface ISideMenu {
fileExplorerInfo: IFileExplorerState;
}
So now in my App class I am trying to render the SideMenu component, but typescript displays an error saying that I am not passing the prop fileExplorerInfo into that component. I would prefer not to have to do this due to redux populating that prop for me to use from the store's state. Does anybody have a recommendation on how I can handle this better?
class App extends Component {
render() {
return (
<div>
<SideMenu />
</div>
);
}
}
You missed the order of the types in connect function
connect<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = {}>
TStateProps comes from state in mapStateToProps
TOwnProps comes from outside
You should use connect like this:
export default connect<ISideMenu, {}, {}, IFileExplorerState>(mapStateToProps, {})(SideMenu);
Or you can leave empty the "generic part"
export default connect(mapStateToProps, {})(SideMenu);

React Native - navigation issue "undefined is not an object (this.props.navigation.navigate)"

Im following this tutorial https://reactnavigation.org/docs/intro/ and im running into a bit of issues.
Im using the Expo Client app to render my app every time and not a simulator/emulator.
my code is seen down below.
I originally had the "SimpleApp" const defined above "ChatScreen" component but that gave me the following error:
Route 'Chat' should declare a screen. For example: ...etc
so I moved the decleration of SimpleApp to just above "AppRegistry" and that flagged a new error
Element type is invalid: expected string.....You likely forgot to export your component..etc
the tutorial did not add the key words "export default" to any component which I think it may have to do with the fact that im running it on the Expo app? so I added "export default" to "HomeScreen" and the error went away.
The new error that I cant seem to get rid off(based on the code below) is the following:
undefined is not an object (evaluating 'this.props.navigation.navigate')
I can't get rid of it unless I remove the "{}" around "const {navigate}" but that will break the navigation when I press on the button from the home screen
import React from 'react';
import {AppRegistry,Text,Button} from 'react-native';
import { StackNavigator } from 'react-navigation';
export default class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Text>Hello, Chat App!</Text>
<Button
onPress={() => navigate('Chat')}
title="Chat with Lucy"
/>
</View>
);
}
}
class ChatScreen extends React.Component {
static navigationOptions = {
title: 'Chat with Lucy',
};
render() {
return (
<View>
<Text>Chat with Lucy</Text>
</View>
);
}
}
const SimpleApp = StackNavigator({
Home: { screen: HomeScreen },
Chat: { screen: ChatScreen },
});
AppRegistry.registerComponent('SimpleApp', () => SimpleApp);
Additional Info:
When you are nesting child components, you need to pass navigation as prop in parent component.
//parent.js
<childcomponent navigation={this.props.navigation}/>
And you can access navigation like this
//child.js
this.props.navigation.navigate('yourcomponent');
Reference: https://reactnavigation.org/docs/en/connecting-navigation-prop.html
With Expo you should't do the App registration your self instead you should let Expo do it, keeping in mind that you have to export default component always:
Also you need to import View and Button from react-native: please find below the full code:
import React from 'react';
import {
AppRegistry,
Text,
View,
Button
} from 'react-native';
import { StackNavigator } from 'react-navigation';
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Text>Hello, Chat App!</Text>
<Button
onPress={() => navigate('Chat', { user: 'Lucy' })}
title="Chat with Lucy"
/>
</View>
);
}
}
class ChatScreen extends React.Component {
// Nav options can be defined as a function of the screen's props:
static navigationOptions = ({ navigation }) => ({
title: `Chat with ${navigation.state.params.user}`,
});
render() {
// The screen's current route is passed in to `props.navigation.state`:
const { params } = this.props.navigation.state;
return (
<View>
<Text>Chat with {params.user}</Text>
</View>
);
}
}
const SimpleAppNavigator = StackNavigator({
Home: { screen: HomeScreen },
Chat: { screen: ChatScreen }
});
const AppNavigation = () => (
<SimpleAppNavigator />
);
export default class App extends React.Component {
render() {
return (
<AppNavigation/>
);
}
}
As Bobur has said in his answer, the navigation prop isn't passed to children of the routed component. To give your components access to navigation you can pass it as a prop to them, BUT there is a better way.
If you don't want to pass the navigation prop all the way down your component hierarchy, you can use useNavigation instead. (Which in my opinion is just cleaner anyways, and reduces the amount of code we have to write):
function MyBackButton() {
const navigation = useNavigation();
return (
<Button
title="Back"
onPress={() => {
navigation.goBack();
}}
/>
);
}
https://reactnavigation.org/docs/use-navigation/
This is just really nice because if you have multiple levels of components you wont have to continuously pass the navigation object as props just to use it. Passing navigation just once requires us to 1. Add a prop to the component we want to pass it to. 2. Pass the prop from the parent component. 3. Use the navigation prop to navigate. Sometimes we have to repeat steps 1 and 2 to pass the prop all the way down to the component that needs to use navigation. We can condense steps 1 and 2, no matter how many times they are repeated, into a single useNavigation call with this method.
I think it is best.
Try this Code: onPress={() => this.props.navigation.navigate('Chat')}
<ChildComponent navigation={props.navigation} {...data} />
This will make the navigation from the parent propagated to the subsequent child navigations.
const AppNavigation =()=>{ <SimpleApp />}
export default class App extends React.Componet{
render(){
return (
<AppNavigation/>
);
}
}

Calling function from another component

I am using React v0.14.8. I tried to call the fetchData function from another component. Here is my code:
export default class TagUtils extends React.Component {
deleteTag = () => {
Tags.deleteTag(this.props.tag).then(function(response){
if(response.message === 'tag successfully deleted')
Sidebar.fetchData();
});
}
// other codes
And:
export default class Sidebar extends React.Component {
fetchData() {
Tags.getTags().done((response) => {
this.setState({tags: response.tags || [], loaded: true});
});
}
//other codes
When I called deleteTag, I got this error in my console:
TypeError: _SidebarJsx2.default.fetchData is not a function
You can't call Sidebar.fetchData because fetchData is not a static member of Sidebar, it is an instance member. This means you need an instance of Sidebar to call fetchData on, for example new Sidebar().fetchData(). Of course, this is not how a React component is supposed to be used, and it would not set state on all other Sidebar instances, so it wouldn't be meaningful.
What you want to do is pass a callback to your TagUtils component:
export default class TagUtils extends React.Component {
deleteTag = () => {
Tags.deleteTag(this.props.tag).then((response) => {
if(response.message === 'tag successfully deleted')
this.props.onDeleteTag();
});
}
}
export default class Sidebar extends React.Component {
fetchData() {
Tags.getTags().done((response) => {
this.setState({tags: response.tags || [], loaded: true});
});
}
render() {
return (
{ this.state.tags.map((tag) =>
<TagUtils tag={tag} onDeleteTag={this.fetchData} />) }
);
}
}
If you have to thread this callback through several layers of components that's okay, that's typical in React. However, if you find yourself passing a lot of stuff down props through many component layers that seem out of place, or trying to reconcile changes across large horizontal spaces in your app, this is a primary use-case for things like Flux and Redux.

Categories