function not found after mapDispatchToProps - reactjs

Hi to all react geniuses. I am a newbie and I am trying to achieve a very simple thing here.
Below is the code, which tries to call a function sentTheAlert() on button click. However, I get error in my console.
import React from 'react';
import { connect } from 'react-redux';
import { Button } from 'reactstrap';
import { RouteComponentProps } from 'react-router-dom';
export interface IFancyAlerterProps extends StateProps, DispatchProps, RouteComponentProps<{}> {}
export class FancyAlerter extends React.Component<IFancyAlerterProps> {
handleSubmit= () => {
this.props.sendTheAlert('hello');
};
render() {
return (
<div>
<h1>Today Fancy Alert is {this.props.fancyInfo}</h1>
<Button color="primary" onClick={this.handleSubmit}>
See my Alert
</Button>
</div>
);
}
}
const SEND_MESSAGE = 'SEND_MESSAGE';
interface SendAlertType {
type: typeof SEND_MESSAGE;
payload: string;
}
function sendTheAlert(newMessage: string): SendAlertType {
return {
type: SEND_MESSAGE,
payload: newMessage,
};
}
const mapDispatchToProps = { sendTheAlert };
function mapStateToProps(state) {
return { fancyInfo: 'Fancy this:' + state.currentFunnyString };
}
type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = typeof mapDispatchToProps;
export default connect(mapStateToProps, mapDispatchToProps)(FancyAlerter);
Note: If this information helps, I create a jhispter application with react UI. And tried to add a new component (FancyAlerter). All the old components are able to get my function however, the new component is unable to get this function or any other function.
So, I just don't understand the mechanics I believe. Any help would be really appreciated.
UPDATE: In the above code, the props contains methods from RouteComponentProps but not from the other two types.

It looks like problem about using object for mapDispatchToProps. When you use mapDispatchToProps as an Object you should provide action creator, not void function :
const SEND_MESSAGE = 'SEND_MESSAGE'
interface SendAlertType {
type: typeof SEND_MESSAGE
payload: String
}
function sendTheAlert(newMessage: String): SendAlertType {
return {
type: SEND_MESSAGE,
payload: newMessage
}
}
const mapDispatchToProps = { sendTheAlert };
Later on you can fire an alert on middleware (saga, thunk, etc.).
Check for the usage : https://daveceddia.com/redux-mapdispatchtoprops-object-form/
Test your code : https://codesandbox.io/s/icy-lake-h3rxr?file=/src/CounterMapDispatchObj.js

Thanks for looking into the issue. I figured it out. Of course all your answers helped me eliminate the possible causes.
Seems like how a component is imported makes a lot of difference i the react router file where all the routes were defined.
Supposedly below is my route
<ErrorBoundaryRoute path="/fancy" component={FancyAlerter} />
And the way you import this component is
import FancyAlerter from './modules/fancyalert/fancyalert';
Instead of
import { FancyAlerter } from './modules/fancyalert/fancyalert';

Related

Type InferableComponentEnhancerWithProps is missing the following properties from type Component<OwnProps>

I'm following this tutorial to build a chat app with React and Redux on Typescript, but I'm getting an error when exporting my connected component:
Type 'InferableComponentEnhancerWithProps<ConnectedState & ConnectedDispatch, OwnProps>'
is missing the following properties from type 'Component<OwnProps, {}, any>':
context, setState, forceUpdate, render, and 3 more.
This is the code from the tutorial. In which sense should I update it to get rid of this error and be able to use the component normally.
import * as React from 'react'
import * as redux from 'redux'
import { connect } from 'react-redux'
import { Message as MessageModel, UserMessage} from 'rcserver/src/models'
import { ChatState } from '../state'
import { Action } from '../actions'
import { Messages } from './Messages'
import { ChatInput } from './ChatInput'
interface OwnProps {
socket: WebSocket,
username: string
}
interface ConnectedState {
messages: MessageModel[]
}
interface ConnectedDispatch {}
interface OwnProps {}
const mapStateToProps = (state: ChatState, ownProps: OwnProps): ConnectedState => ({
messages: state.messages
})
const mapDispatchToProps = (dispatch: redux.Dispatch<Action>): ConnectedDispatch => ({})
export class ChatAppComponent extends React.Component<ConnectedState & ConnectedDispatch & OwnProps> {
sendHandler = (message: string) => {
const messageObject: MessageModel = {
name: this.props.username,
message: message
}
this.props.socket.send(JSON.stringify(messageObject))
}
render() {
return (
<div className="container">
<h3>React Chat App</h3>
<Messages username={this.props.username} messages={this.props.messages} />
<ChatInput onSend={this.sendHandler} />
</div>
)
}
}
export const ChatApp: React.Component<OwnProps> = connect(mapStateToProps, mapDispatchToProps)
//This last line is the one triggering the error
It's almost correct, but you forgot to apply connect(mapStateToProps, mapDispatchToProps) to your ChatAppComponent. This should work:
export const ChatApp = connect(mapStateToProps, mapDispatchToProps)(ChatAppComponent)
The type of ChatApp will be inferred correctly, so you don't need a type signature. If you do want the signature, you'll need React.FunctionComponent<OwnProps> though, as the connected component is not a class. Alternatively, you could also use the more general React.ComponentType<OwnProps> which works for both classes and function components.

Calling action creator inside the function. Error:Actions may not have an undefined "type" property?

I know action creator should have a type of property only then it would be able to dispatch. Since I am having a function call which ultimately leads to one action creator which have type property then Why it is showing me this problem.
When I tried to directly dispatch start game action creator it works but since I have to implement some more function inside them so I needed then inside the function.
How to implement the same?
Menu.js
import React, { Component } from 'react';
import {connect} from 'react-redux';
import {startGame} from '../actions';
import {loadMenu} from '../actions';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
const page_Banner={
marginTop:'35px',
fontSize:'45px',
textAlign:'center',
letterSpacing:'20px',
fontWeight:'bold'
};
const spacebar_screen={
marginTop:'35px',
color:'grey'
}
class Menu extends Component {
componentDidMount() {
this.props.dispatch(loadMenu());
console.log(this.props.dispatch);
console.log(this.props.isPlaying);
}
render() {
return (
<div style={page_Banner}>
Redux Tetris
{!this.props.isPlaying?<h2 style={spacebar_screen}>Press spacebar to start the game</h2>:null}
</div>
)
}
}
Menu.propTypes={
isPlaying:PropTypes.bool,
}
// function mapDispatchToProps(dispatch){
// return bindActionCreators({loading:loadMenu},dispatch);
// }
const mapStateToProps = (state) => ({
isPlaying: state.gameStatus.currentState !== 'IDLE',
});
export default connect(mapStateToProps)(Menu);
Action.js
import constants from "../gameConstants/constants";
export const startGame=()=>{
const ShapeMapping=constants;
const current_Shapeno=Math.floor(Math.random()*7);
const next_Shapeno=Math.floor(Math.random()*7);
const current_Shape=ShapeMapping[current_Shapeno];
const next_Shape=ShapeMapping[next_Shapeno];
return {
type:"START_GAME",
current_Shape,
next_Shape
};
}
export const pauseGame = () => ({
type: "PAUSE_GAME",
});
export const unpauseGame = () => ({
type: "UNPAUSE_GAME",
});
export const gameOver = () => ({
type: "GAME_OVER",
});
export const loadMenu=()=>({
function(dispatch,getState){
function handleSpacebar(event){
if(event.keyCode==32){
dispatch(loadGame());
window.removeEventListener('keyup',handleSpacebar);
console.log('here')
}
}
window.addEventListener('keyup',handleSpacebar);
}
})
export const loadGame=()=>({
function (dispatch,getState){
dispatch(startGame());
}
})
The issue is in loadMenu and loadGame action creators. You're returning an object with an anonymous function which doesn't make any sense. An action creator is supposed to return an object with a type and the minimal data to define the action and return a function if you're using redux-thunk.
Keep the actions creators clean like you've done in gameOver and handle everything else in reducers or using the redux pub/sub pattern.
See this answer by Dan Abramov https://github.com/reduxjs/redux/issues/787

Redux Connect with Typescript - TS2347

I'm new to Typescript and though it is fascinating and a life-saver, this error is quite a hard nut to crack.
TypeScript error: Untyped function calls may not accept type arguments. TS2347
Can you please tell me what should be improved in the below class to get rid of this error ?
Here is the whole class
import React, { FunctionComponent } from 'react'
import { ListGroup } from 'react-bootstrap'
import { connect } from 'react-redux'
type StateProps = {
mbzArtists: IMBZArtist[],
releaseArtistID: string
}
type DispatchProps = {
findMBZReleases: (artistID: string) => void,
}
type OwnProps = {}
type MBZSearchResultsProps = StateProps & DispatchProps & OwnProps
const MBZSearchResults: FunctionComponent<MBZSearchResultsProps> = ({ findMBZReleases, mbzArtists, releaseArtistID }) => {
return (
<div className="MBZSearchResults">
// div content
</div>
)
}
const mapStateToProps = (state: AppState) => {
return {
mbzArtists: state.musicBrainz.mbzArtists,
releaseArtistID: state.musicBrainz.artistReleaseID
}
}
const mapDispatchToProps = (dispatch: any): DispatchProps => {
return {
findMBZReleases: (artistID: string) => dispatch(Actions.MBZActions.findMBZReleases(artistID))
}
}
export default connect<StateProps, DispatchProps, OwnProps>(mapStateToProps, mapDispatchToProps)(MBZSearchResults)
In case you require more information, please let me know.
Thanks.
The issue seems to be fixed by changing the export statement as below:
const component: React.FunctionComponent<OwnProps> =
connect(mapStateToProps, mapDispatchToProps)(MBZSearchResults)
export default component
Can I please have a comment from typescript users to let me know if this is the way to go ?
As stated from the error you posted.
TypeScript error: Untyped function calls may not accept type
arguments. TS2347
The connect function dosen't accept type arguments.
Change the export connect to this:
export default connect(mapStateToProps, mapDispatchToProps)(MBZSearchResults)

What is the proper interface for element with "GetWrappedInstance"

I am writting React+Redux with typescript. I need to access the reference of one wrapped instance, like this.refs.items.getWrappedInstance(), but got typescript error Property 'getWrappedInstance' does not exist on type 'ReactInstance'
Which interface shall I give to items? Are there any interface defined by Redux that I can declare or I need to create my own?
I tried to google and search stackoverflow but cannot find an answer.
Thank you!
We got the same error using Flow and our most senior UI developer ultimately said to use // $FlowIgnore: some comment
I think that because accessing wrappedInstance is an antipattern flow and typescript may not support it...yet?
I am interested if anyone has a different answer.
I came across this issue and while I didn't find a native solution, I did manage to create one. Below is a working sample implementation with the solution.
Keep note of the { withRef: true } in the connect function.
Here is a small utility type to add the missing definition.
// connect.ts
type WrappedConnectedComponent<T> = {
getWrappedInstance(): T
}
export function unwrapConnectedComponent<T>(component: T): T | undefined {
if (component) {
const wrappedComponent: WrappedConnectedComponent<T> = component as any
if (wrappedComponent.getWrappedInstance) {
return wrappedComponent.getWrappedInstance()
}
}
return undefined
}
Here is a simple component that we'll be accessing later.
// SomeOtherComponent.tsx
import * as React from 'react'
import { connect } from 'react-redux'
class SomeOtherComponent extends React.Component {
log = () => {
console.log('logged')
}
render() {
return <div />
}
}
const mapStateToProps = () => ({})
const mapDispatchToProps = () => ({})
const ConnectedSomeOtherComponent = connect(
mapStateToProps,
mapDispatchToProps,
null,
{ withRef: true } // Important
)(SomeOtherComponent)
export default ConnectedSomeOtherComponent
export { SomeOtherComponent }
Here is the main component that does all the work.
// SomeComponent.tsx
import * as React from 'react'
import ConnectedSomeOtherComponent, { SomeOtherComponent } from './SomeOtherComponent'
import { unwrapConnectedComponent } from './connect'
class SomeComponent extends React.Component {
someOtherComponent?: SomeOtherComponent
private setSomeOtherComponent = (someOtherComponent: SomeOtherComponent) => {
this.someOtherComponent = unwrapConnectedComponent(someOtherComponent)
}
onClick = () => {
if (this.someOtherComponent) {
this.someOtherComponent.log()
}
}
render() {
return (
<div>
<button onClick={this.onClick} />
<ConnectedSomeOtherComponent ref={this.setSomeOtherComponent} />
</div>
)
}
}
export default SomeComponent

Typescript: passing function as type in interface

I am trying to figure out how to get type out of existing Typescript function and use it to define interface. I am working on React project and I want to pass action creator (function) to Props interface and then into React Component as Component<Props, State>.
Example action creator:
export function myFunction(foo: string = "bar") {
return {
type: "EXAMPLE_ACTION",
payload: foo,
}
}
Example component:
import React, { Component } from 'react'
import { connect } from "react-redux"
import { myFunction } from "actions"
export interface Props {
// This is what I'm trying to and and it ends up in ts error
myFunc: myFunction
}
class SomeComponent extends Component<Props, {}> {
render() {
return (
<div>
Example:
<button onClick={this.props.myFunc("baz")}>Click to dispatch</button>
</div>
)
}
}
export default connect(null, {
myFunction
})(SomeComponent)
I was thinking this could work, but frankly it's a typescript error:
[ts] Cannot find name 'myFunction'
I was wondering if i have to define a separate type to pass it to my component, something like this:
export type myFuncType = (foo: string) => { type: string, payload: string }
export const myFunction: myFuncType = (foo: string) => {
return {
type: "EXAMPLE_ACTION",
payload: foo,
}
}
but that seems too verbose and redundant and would need to import another export. Is there any other way around this?
You can use the typeof keyword in type position to obtain the type of a named value.
In this case you would write
import { myFunction } from "actions";
export interface Props {
myFunc: typeof myFunction;
}
The reason you currently receive an error is that TypeScript has two distinct declaration spaces, one for values and one for types. function defines a value but not a type.

Resources