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.
Related
I've got a parent component Course that is able to get state from redux and I'm able to log that out successfully:
import React, { Component } from "react";
import { connect } from "react-redux";
import SchoolWrapper from "../SchoolWrapper";
export class Course extends Component {
constructor(props) {
super(props);
console.log("Props in course", props);
}
render() {
return (
<>
<SchoolWrapper>Wrapped component</SchoolWrapper>
</>
);
}
}
const mapStateToProps = (state) => ({
user: state.user,
});
export default connect(mapStateToProps)(Course);
Nested in the Course component is another component SchoolWrapper that is able to get props from redux state:
import React, { Component } from "react";
import { connect } from "react-redux";
import { Nav } from "./Student/Nav";
export class SchoolWrapper extends Component {
constructor(props) {
super(props);
console.log("SchoolWrapper props", props);
}
render() {
return (
<>
<Nav />
</>
);
}
}
const mapStateToProps = (state) => ({
user: state.user,
});
export default connect(mapStateToProps)(SchoolWrapper);
However, the Nav component or any other component nested at this level is not able to access state from redux.
import React, { Component } from "react";
import { connect } from "react-redux";
export class Nav extends Component {
constructor(props) {
super(props);
console.log("Nav props: ", props);
}
render() {
return (
<div>
nav goes here...
</div>
);
}
}
const mapStateToProps = (state) => ({
user: state.user,
});
export default connect(mapStateToProps)(Nav);
Where am I going wrong?
I think you're importing Nav wrong, here you're using a "default" export:
export default connect(mapStateToProps)(Nav);
But you try to use a "named" import:
import { Nav } from "./Student/Nav";
Nav should be imported as a "default":
import Nav from "./Student/Nav"
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';
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 {
...
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)
}
I have a parent component that I want to be tabs for multiple children. For some reason, my child component has more props data than the parent.
Parent component
import React, { Component} from 'react';
import { Link } from 'react-router';
import { connect } from 'react-redux';
class TerritoryTabs extends Component {
componentWillMount() {
console.log('this is the parent props (tabs)')
console.log(this.props);
}
render() {
return (
{this.props.children}
);
}
}
export default connect(null, null)(TerritoryTabs);
Child component
import React, { Component} from 'react';
import { Link } from 'react-router';
import { connect } from 'react-redux';
import { reduxForm } from 'redux-form';
import { getTerritoryGeographies } from '../actions/index';
import TerritoryTabs from './territory-tabs';
class TerritoryGeographyList extends Component {
componentWillMount() {
console.log('this is child props (TerritoryGeographyList)');
console.log(this.props);
this.props.getTerritoryGeographies(this.props.params.id);
}
render() {
return (
<TerritoryTabs>
<div>This list goes here</div>
</TerritoryTabs>
);
}
}
function mapStateToProps(state) {
return { territoryGeographies: state.territoryGeographies.all
};
}
export default connect(mapStateToProps, { getTerritoryGeographies })(TerritoryGeographyList);
Here is what the console prints.
The wrap component should be called "parent". Example:
<Parent>
<Child />
</Parent>
So, in your case, fix this line:
class TerritoryTabs extends Component {
componentWillMount() {
console.log('this is the child props (tabs)') // <-- Fix this line, it should be the "child"
console.log(this.props);
}
and this line:
class TerritoryGeographyList extends Component {
componentWillMount() {
console.log('this is parent props (TerritoryGeographyList)'); // <-- fix this line, it should be "parent"
console.log(this.props);
this.props.getTerritoryGeographies(this.props.params.id);
}