Timothy
Timothy

Reputation: 4285

How to pass props using Redux connect

Im trying to pass strings and a child component using redux props as follows below. I get the error "TypeError: Cannot read property circularImage of undefined"

import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { View, Text, Image } from 'react-native'

// CircularImage.js
function CircularImage () {
  return (
    <Image source={this.props.imageSourceUrl} style={{width: 100, height: 100}} /> // Rounded Img
  )
}
CircularImage.propTypes = {
  imageSourceUrl: PropTypes.string.isRequired
}

function mapStateToProps1(state, ownProps) {
  return {
    imageSourceUrl: require('../images/icon.png')
  }
}

CircularImage = connect(mapStateToProps1)(CircularImage);

// ScreenHeaderWithImage.js
function ScreenHeaderWithImage () {
  return (
    <View style={{flex: 1, padding: 50}}>
      <View style={{marginBottom: 50}}>
        {this.props.circularImage}
      </View>
      <Text style={{ fontSize: 20 }}>{this.props.primaryHeadline}</Text>
      <Text style={{ fontSize: 10 }}>{this.props.secondaryHeadline}</Text>
    </View>
  )
}
ScreenHeaderWithImage.propTypes = {
  primaryHeadline: PropTypes.string.isRequired,
  secondaryHeadline: PropTypes.string, // Optional
}

function mapStateToProps2(state, ownProps) {
  return {
    primaryHeadline: 'Timothy Max',
    secondaryHeadline: 'Kenya',
    circularImage: CircularImage
  }
}

ScreenHeaderWithImage = connect(mapStateToProps2)(ScreenHeaderWithImage);

export default ScreenHeaderWithImage

Upvotes: 3

Views: 2089

Answers (3)

Timothy
Timothy

Reputation: 4285

I needed to change a number of things:

  1. Pass "props" as an argument to both functional components
  2. Change the image propType

On the ScreenHeaderWithImage component:

  1. Add a proptype for the circularImage component
  2. Map this prop as a function that returns the component
  3. Invoke the function

See the comments in the code below:

import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux';
import { View, Text, Image } from 'react-native'

// CircularImage.js
function CircularImage (props) { // 1.
  return (
    <Image source={ props.imageSourceUrl } style={{ width: 100, height: 100 }} /> 
  )
}
CircularImage.propTypes = {
  imageSourceUrl: Image.propTypes.source // 2.
}

function mapStateToProps1() {
  return {
    imageSourceUrl: require('../images/icon.png')
  }
}

CircularImage = connect(mapStateToProps1)(CircularImage);

// ScreenHeaderWithImage.js
function ScreenHeaderWithImage (props) { // 1.
  return (
    <View style={{flex: 1, padding: 50}}>
      <View style={{marginBottom: 50}}>
        { props.circularImage() /* 5. */ } 
      </View>
      <Text style={{ fontSize: 20 }}>{ props.primaryHeadline }</Text>
      <Text style={{ fontSize: 10 }}>{ props.secondaryHeadline }</Text>
    </View>
  )
}
ScreenHeaderWithImage.propTypes = {
  primaryHeadline: PropTypes.string.isRequired,
  secondaryHeadline: PropTypes.string, 
  circularImage: PropTypes.func.isRequired, // 3.
}

function mapStateToProps2() {
  return {
    primaryHeadline: 'Timothy Max',
    secondaryHeadline: 'Kenya',
    circularImage: () => <CircularImage /> // 4.
  }
}

ScreenHeaderWithImage = connect(mapStateToProps2)(ScreenHeaderWithImage);

export default ScreenHeaderWithImage

Upvotes: 1

nicecatch
nicecatch

Reputation: 1737

try extending from component

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Image } from 'react-native'

class CircularImage extends Component {   
  return (
    <Image source={this.props.imageSourceUrl} style={{width: 100, height: 100}} /> // Rounded Img
  )
}
CircularImage.propTypes = {
  imageSourceUrl: PropTypes.string.isRequired
}

function mapStateToProps(state, ownProps) {
  return {
    imageSourceUrl: require('../images/icon.png')
  }
}

export default connect(mapStateToProps, null)(CircularImage);

it gets clearer on what you are trying to accomplish

Anyway in this case you don't need mapStateToProps because you don't have any props depending on state (if you are planning to pass imageSourceUrl as a prop by You can simply export CircularImage without connecting it

this is probably what you need:

CircularImage:

export default class CircularImage extends Component {   
  return (
    <Image source={this.props.imageSourceUrl} style={{width: 100, height: 100}} /> // Rounded Img
  )
}
CircularImage.propTypes = {
  imageSourceUrl: PropTypes.string.isRequired
}

ScreenHeaderWithImage:

export default class ScreenHeaderWithImage extends Component {
  return (
    <View style={{flex: 1, padding: 50}}>
      <View style={{marginBottom: 50}}>
        <CircularImage imageSourceUrl={require('../images/icon.png')}
      </View>
      <Text style={{ fontSize: 20 }}>{this.props.primaryHeadline}</Text>
      <Text style={{ fontSize: 10 }}>{this.props.secondaryHeadline}</Text>
    </View>
  )
}
ScreenHeaderWithImage.propTypes = {
  primaryHeadline: PropTypes.string.isRequired,
  secondaryHeadline: PropTypes.string, // Optional
}

You don't have props depending on state in ScreenHeaderWithImage as well, so you don't need to connect it

Just pass them down to the element when you use it

Upvotes: 1

Moti Korets
Moti Korets

Reputation: 3748

When using a function component the function should receive the props as parameters. Like this

function ScreenHeaderWithImage (props) {
   ...
   <View style={{marginBottom: 50}}>
    {props.circularImage}
   </View>
   ....
}

Upvotes: 2

Related Questions