0

I am very new to react... I have a parent component that represents the background for my webapp. I use Match from react-router to handle when the user navigates to different routes.

The new route renders the PageView component, which I want to have a different background image. So to do this I set the background image of it's parent by passing a function from the parent to he child's props and then calling it in the child from componentDidMount()

This does not work and gives me Maximum call stack exceeded error

Here is my parent component:

class App extends Component {
  constructor () {
    super()
    this.state = {
      backgroundImage: '../public/img/initial.jpg'
    }

    this.changeBackground = this.changeBackground.bind(this)
  }
  changeBackground (backgroundImage) {
    this.setState({
      backgroundImage
    })
  }
  render () {
    return (
      <BrowserRouter>
        <Provider store={store}>
          <div className='app' style={{backgroundImage: `url(${this.state.backgroundImage})`}}>
            <div className='overlay'>
              <Match exactly pattern='/' component={() => <Landing />}
              />
              <Match
                pattern='/healthcare'
                component={(props) => <PageView descriptionText='Healthcare Solutions'
                  backgroundImage='../public/img/5.png' changeParentBackground={this.changeBackground} {...props} />}
              />
              <Match
                pattern='/officeofthefuture'
                component={(props) => <PageView descriptionText='Office of the Future'
                  backgroundImage='../public/img/1.png' changeParentBackground={this.changeBackground} {...props} />}
              />
            </div>
          </div>
        </Provider>
      </BrowserRouter>
    )
  }
}

And here is my child component PageView

class PageView extends Component {
  componentDidMount () {
    const { backgroundImage, changeParentBackground } = this.props
    changeParentBackground(backgroundImage)
  }
  render () {
    const { descriptionText } = this.props
    console.log(this.props.changeParentBackground)
    return (
      <div className='outerDiv'>
        <LeftDesign show />
        <RightDesign descriptionText={descriptionText} />
      </div>
    )
  }
}

RightDesign:

class RightDesign extends Component {
  render () {
    const { descriptionText } = this.props
    return (
      <div className='rightDiv'>
        <div id='bigCircle'>
          <div className='bigCircleTextDiv'>
            <h1 className='bigCircleText'>{descriptionText}</h1>
          </div>
        </div>
      </div>
    )
  }
}

LeftDesign

class LeftDesign extends Component {
  constructor (props) {
    super(props)
    const { show } = this.props
    this.state = {show}
  }
  render () {
    return (
      <div className='leftDivContainer'>
        <div className='leftDiv'>
          {this.state.show && <WelcomeMsg />}
        </div>
      </div>
    )
  }
}
coder4lyf
  • 927
  • 1
  • 17
  • 36
  • this code looks ok, i think problem is in either `LeftDesign` or `RightDesign` component, can you show these components also ? – Mayank Shukla Apr 18 '17 at 20:02
  • @MayankShukla Please see the edited question I added the components – coder4lyf Apr 18 '17 at 20:59
  • So you could read the Location property object of the parent to determine which page you are on. Split the 'this.props.location.pathname' by '/' and pull the second array item to find your first level route string and use a switch statement to determine the background image. – Michael Lyons Apr 18 '17 at 22:14

1 Answers1

0

I commented earlier about this sort of solution.

It uses CSS background images and transitions to switch the image based on what the string of the location's pathname's second item is, which would correspond to the first-level routes of your app.

function getBackground(array) {
  switch(array[1]) { 
   case 'healthcare':
    return 'www.foo.com/image/1.jpg';
   case 'officeofthefuture':
    return 'www.foo.com/image/2.jpg';
   default:
    return 'www.foo.com/image/default.jpg'
  }
}

export default class Parent extends Component {
  render() {
   let { location } = this.props;

   // Split the pathname string into an array of sub-paths
   let locationArray = location ? location.pathname.split('/') : [];

   // Determine the Background URL
   let backgroundUrl = getBackground(locationArray);
   // Define the Parent Style
   const parentStyle = {
     transition: 'all 0.2s ease-out',
     backgroundImage: "url('"+backgroundUrl+"')",
     backgroundPosition: 'center',
     backgroundSize: 'contain',
     backgroundRepeat: 'no-repeat'
   };
   return <div style={parentStyle}>
            {this.props.children}
          </div>
  }
}
Michael Lyons
  • 584
  • 3
  • 10
  • Thanks! This works..but with one problem. When I refresh any of the routes I get the following "Warning: warning.js:36 Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is..." How to fix? – coder4lyf Apr 24 '17 at 14:23
  • Are you using server side rendering (Universal/Isomorphic)? – Michael Lyons Apr 24 '17 at 19:29
  • Universal rendering – coder4lyf Apr 24 '17 at 19:53
  • Okay, check out this [link](http://stackoverflow.com/questions/33521047/warning-react-attempted-to-reuse-markup-in-a-container-but-the-checksum-was-inv). You may have to wrap your server-side rendered content in a div to compensate for how React renders on the client side. Edit: Look at James Wright's answer, it's not marked but it's the top answer. – Michael Lyons Apr 24 '17 at 19:55
  • So after reading around a bit, and actually reading the whole article I just linked (whoops), this may be an issue if you're using some auto-prefixer combined with inline styles. It would be hard to guess exactly what could be throwing this error. I apologize, the answer I wrote works in a non-universal solution as far as I'm aware. – Michael Lyons Apr 24 '17 at 20:58
  • it still works, but I get that warning. The warning tells me the diff..basically the client has url('www.foo.com/image/1.jpg') but the server has url('www.foo.com/image/default.jpg'). The server has the default but the client has the right image. – coder4lyf Apr 24 '17 at 21:24
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/142549/discussion-between-michael-lyons-and-coder4lyf). – Michael Lyons Apr 24 '17 at 21:32