Typescript constraints with redux connect - reactjs

Using typescript for react as the language i have declared a class with constraints . I need to apply the connect method to it
import * as React from 'react';
import { connect } from 'react-redux';
import { initAskadeFiles } from '../Entities/Askade/Askade.Actions';
import { Dispatch } from 'redux';
interface IProp<T> {
PropOne: T
}
interface IState<T> {
StateOne: T
}
class BaseEdit<T> extends React.Component<IProp<T>, IState<T>> {
}
export function mapDispatchToProps(dispatch: Dispatch, ownProps: any) {
return {
InsertItem: () => dispatch(initAskadeFiles())
}
}
export default connect(null, mapDispatchToProps)(BaseEdit);
And in the calling component below is the syntax
import * as React from 'react';
import BaseEditSample from './BaseEditSample';
import { City } from '../Components/GridFunctionality/City';
export class ComplexEditSample extends React.Component {
public render(): any {
<BaseEditSample<City> />
}
}
When i use the syntax with City being passed to it i get an error
what am i missing in this i need redux to be connected to this component along with the contraints? Thanks
[ts] Expected 0 type arguments, but got 1.

First, you can pass your actions directly to the connect without mapDispatchToProps like this:
export default connect(mapStateToProps, { state, actions })(Component);`
And in your component use the imported actions and states:
type ComponentProps = {state, actions};
export default class Component extends React.Component<ComponentProps> {
render() {
const {
data,
actions,
} = this.props
return (...)
}

Related

How to Call a Function From Another Class With React-Redux?

I want to call functions from another class in react.Js and I did it successfully. My problem is that I get Error: You must pass a component to the function returned by connect. Instead received {"refs":{},"updater":{}} if I use react-redux. Here is a basic example of algortihm
import { Component } from "react";
import { GetCityListFromActiveAddressSource } from '../Services/AddressService'
import { connect } from 'react-redux';
class FirstClass extends Component{
constructor(props){
super(props);
}
TestFunction(){
alert("test");
}
render(){
return null
}
}
const mapStateToProps = ({ Modules }) => {
const { GetDynamicMenuList } = Modules;
return { GetDynamicMenuList }
}
const Address = new AddressService();
export default connect(mapStateToProps,{GetCityListFromActiveAddressSource})(Address);
//export default Address;
And My Second class...
import React, { Component } from 'react';
import FirstClass from '../../../ServiceClient/FirstClass';
class SeconClass extends Component {
constructor(props) {
super(props);
}
componentDidMount(){
Address.TestFunction();
}
}
If I don't use connect and react-redux then I can call my function. But I have to use react-redux.
I solved my problem, My problem was that I used export default with const value but react-redux(connect) needs a component or function But I unfortunatelly used const value in my example. That's why I got error. Then I exported my component in connect and I used another export for my const. It works well enough for me.
import React, { Component } from "react";
import { GetCityListFromActiveAddressSource } from '../Services/AddressService'
import { connect } from 'react-redux';
class AddressService extends Component{
constructor(props){
super(props);
}
TestFunction(){
alert("test");
}
render(){
return null
}
}
const mapStateToProps = ({ Modules }) => {
const { GetDynamicMenuList } = Modules;
return { GetDynamicMenuList }
}
export default connect(mapStateToProps,{GetCityListFromActiveAddressSource})
(AddressService);
export const Address = new AddressService();
And I call my function like
import {Address} from '../../../ServiceClient/Address';

Embedded Child Component in React is Undefined

I have the following parent component:
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
import _ from "lodash";
import ChildComponent from "./ChildComponent";
class ParentComponent extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<div>
I'm at Parent
<ChildComponent/>
</div>
);
}
}
function mapStateToProps(state) {
return { }
}
export default connect(mapStateToProps, null)(ParentComponent);
Inside the parent has a component called ChildComponent that looks like this:
import React, { Component, PropTypes } from "react";
import { connect } from "react-redux";
import { reduxForm } from "redux-form";
import { bindActionCreators } from "redux";
class ChildComponent extends Component {
constructor(props) {
super(props);
}
componentWillMount() {
}
render() {
return (
<div>
at the child
</div>
);
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
},
dispatch
);
}
function mapStateToProps(state) {
return {
};
}
export default connect(mapStateToProps, mapDispatchToProps)(
ChildComponent
);
When I try adding the child component I keep getting this error:
But if I click continue the page turns back to normal. I don't understand how the child component is undefined. It's just embedded and does not include any props.
UPDATE:
I'm not getting the error anymore but I notice my page turns blank when I open this particular component. I'll be doing a bit more troubleshooting.
I tried out your code, and it works fine for me. My thought was maybe what your entry file looks like? or file structure? If you like you can try the following syntax for the parent and child - it worked this way as well:
Child:
const mapStateToProps = () => {
return {}
}
const ConnectedChildComponent = connect(
mapStateToProps,
{})(ChildComponent)
export default ConnectedChildComponent;
Parent:
const mapStateToProps = () => {
return {}
}
const ConnectedParentComponent = connect(
mapStateToProps,
{})(ParentComponent)
export default ConnectedParentComponent;
In your ParentComponent change:
import ChildComponent from "./ChildComponent";
to
import ChildComponent from "./ChildComponent.jsx";
i.e. add the missing ".jsx" extension. Your code is most likely determining the import to be a ".js" file by default, whereas it's actually a ".jsx" file.

Creating an HOC for React Component

I'm trying to create an HOC component for a presentational component and having a bit of trouble with the syntax.
Let's say my presentational component is called BlogViewerBase and let's call the HOC component BlogViewerHoc. I want the following:
I want to include some handler functions in my HOC component
I want the HOC component to connect to my Redux store, get state and pass it to the base component
Does this code look right?
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
// Actions
import * as myActions from '../actions/myActions';
// Base component
import BlowViewerBase from '../components/blogViewerBase';
function hocBlogViewer(BlogViewerBase) {
return class BlogViewerHoc extends React.Component {
handlerFunction1() {
// Some logic here
}
handlerFunction2() {
// Some logic here
}
render() {
return <BlogViewerBase {...this.props} />
}
}
}
function mapStateToProps(state) {
return {
var1: state.module.variable1,
var2: state.module.variable2
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(myActions, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(BlogViewerHoc(BlogViewerBase));
Where I'm struggling is that the examples of HOC components I've come across look more like functions and I think I'm forming mine more like a component so not sure if I'm connecting to the store the right way. Not sure if the mapPropsToState, mapDispatchToState and the handler functions are in the right places.
Define your HOC and then pass your presentational component to it. Also, you can bind an action creator to your props in mapDispatchToProps. Something like:
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { myActionCreator } from 'yourPathToYourActions';
// Actions
import * as myActions from '../actions/myActions';
// Base component
import BlowViewerBase from '../components/blogViewerBase';
function hocBlogViewer(WrappedComponent) {
return class extends React.Component {
handlerFunction1() {
// Some logic here
}
handlerFunction2() {
// Some logic here
}
componentDidMount() {
// I can dispatch this action now
this.props.myActionInProps();
}
render() {
return <WrappedComponent {...this.props} />
}
}
}
function mapStateToProps(state) {
return {
var1: state.module.variable1,
var2: state.module.variable2
};
}
function mapDispatchToProps(dispatch) {
return {
myActionInProps: dispatch(myActionCreator())
};
}
export default connect(mapStateToProps, mapDispatchToProps)(hocBlogViewer(BlowViewerBase));
Your code seems to be OK to me :)
Maybe for simplicity of reading I would do the following adjustments (but this is just my opinion):
const connector = connect(mapStateToProps, mapDispatchToProps)
...
export default function hocBlogViewer(BlogViewerBase) {
return connector(
class BlogViewerHoc extends React.Component {
...

How to wrap multi actionCreators into one props?

I'm getting the following error:
Uncaught TypeError: this.props.dispatch is not a function
Here's my component:
import React from 'react';
import PropTypes from 'prop-types';
import {Link} from 'react-router-dom';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import * as jobTitleSkillsActions from '../../actions/jobTitleSkillsActions';
import SkillList from './SkillList';
import * as userPositionActions from '../../actions/userPositionActions';
class SkillPage extends React.Component {
componentDidMount() {
this.props.dispatch(userPositionActions.loadUserPositions());
var job_title_id = this.props.user_positions[0].job_title_id; this.props.dispatch(jobTitleSkillsActions.loadJobTitleSkills(job_title_id));
}
.....
const mapStateToProps = state => {
return {
job_title_skills: state.job_title_skills,
user_positions: state.user_positions
};
};
function mapDispatchToProps(dispatch) {
return {
actions: {
userPositionActions: bindActionCreators(userPositionActions, dispatch),
jobTitleSkillsActions: bindActionCreators(jobTitleSkillsActions, dispatch),
}
};
}
export default connect(mapStateToProps, mapDispatchToProps)(SkillPage);
What am I doing wrong here?
Per my comment, this would be the correct syntax to bind multiple sub-objects worth of action creators:
function mapDispatchToProps(dispatch) {
return {
userPositionActions : bindActionCreators(userPositionActions, dispatch),
jobTitleSkillsActions: bindActionCreators(jobTitleSkillsActions, dispatch),
}
}
Since you have already used mapDispatchToProps, dispatch wont be available to the component as a prop. Since you have used mapDisptachToProps, the jobs actions will be available as props and you can use them like
componentDidMount() {
this.props.actions.userPositionActions.loadUserPositions());
var job_title_id = this.props.user_positions[0].job_title_id;
this.props.actions.jobTitleSkillsActions.loadJobTitleSkills(job_title_id));
}
However you can simplify it further like
function mapDispatchToProps(dispatch) {
return bindActionCreators({userPositionActions, jobTitleSkillsActions}, dispatch)
}
...
componentDidMount() {
this.props.userPositionActions.loadUserPositions());
var job_title_id = this.props.user_positions[0].job_title_id;
this.props.jobTitleSkillsActions.loadJobTitleSkills(job_title_id));
}
As you have provided mapDispatchToProps to connect function, dispatch is not passed as prop to your component.
Your componentDidMount code should be like this:
componentDidMount() {
const actions = this.props.actions
actions.userPositionActions.loadUserPositions()
var job_title_id = this.props.user_positions[0].job_title_id;
actions.jobTitleSkillsActions.loadJobTitleSkills(job_title_id)
}

action passed down from connect decorator is initially undefined

I have the following smart component and I am specifying the initialUpload function is a required func:
import React, { Component, PropTypes } from 'react';
import UploadForm from '../../components/UploadForm/UploadForm';
import HeaderSelection from '../../components/HeaderSelection/HeaderSelection';
import { initialUpload } from '../../redux/modules/Upload';
import { connect } from 'react-redux';
console.log(typeof initialUpload); //function
#connect((state) => {
return {
file: state.getIn(['upload', 'file'])
};
}, {
initialUpload
})
export default class Home extends Component {
static propTypes = {
initialUpload: PropTypes.func.isRequired
};
render() {
return (
<div>
<UploadForm handleFilesChange={this.props.initialUpload}/>
<HeaderSelection/>
</div>
);
}
}
But I get the error message:
warning.js:36Warning: Failed prop type: The prop initialUpload is
marked as required in Connect(Home), but its value is undefined.
The function is wrapped in dispatch and passed down the component hierarchy fine so I am confused as to what is going on.
#connect is assigning the static propTypes to the resulting rapping component and not to Home itself, which is rather a weird behaviour! I think it is caused by ES7 transformation, this behaviour was not present in previous versions
A work around is to define the propTypes on the wrappedComponent outside class definition:
#connect(...)
export default Home extends Component{
render() {
// ....
}
}
Home.WrappedComponent.propTypes = {
initialUpload: PropTypes.func.isRequired
}
another option would be not to use the decorator & use connect directly

Resources