0
votes

I am trying to learn Styled Component's rendering based off props. I am just trying to create a simple Nav bar. Yes, I do realize that you can set links active by using React Router based off the location. This is more of just a learning experience for me.

class Nav extends Component {
  constructor (props) {
    super(props)

    this.state = {
      isActive: 0
    }
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick (n) {
    console.log('Hello There')

    this.setState = {
      isActive: n
    }
  }

  render () {
    const NAV = styled.div`
      display: flex;
      flex-direction: row;
      justify-content: space-between;
      width: 100%;
      background-color: black;
    `
    const SPAN = styled.span`
      font-size: 3.5vmin;
      cursor: pointer;
      color: white;
      ${props =>
    props.selected &&
        css`
          color: cornflowerblue;
        `}
    `
    const TEXT = styled.p``

    return (
      <NAV links={this.props.links}>
        {this.props.links.map((i, ii) => (
          <SPAN
            onClick={e => this.handleClick(ii)}
            key={ii}
            selected={this.state.isActive === ii ? true : ''}
          >
            <TEXT>{i}</TEXT>
          </SPAN>
        ))}
      </NAV>
    )
  }
}

I am trying to make the link active by changing it's text color. When I map over the links I provide the Nav, if the index of the array if equal to the active state, I make that link active.

Then, onClick, I update the state's isActive to the index that was selected. Needless to say, it's not working. I guess the map's index is only available at render and not at the onClick event. I am not sure what to pass the handleClick function, however.

The App is rendering on my local environment just fine. I made a Codepen with the example, but it's not rendering on there. I've never used Codepen for React, here is the link: https://codepen.io/anon/pen/daqGQQ

Also, I realize I can use the className prop to make a CSS class to give the selected link an active status, but, I'd rather learn the 'styled components' way.

Any help would be much appreciated. Thanks

EDIT

Reformat based on comment:

import React, { Component } from 'react'
import styled, { css } from 'styled-components'

const NAV = styled.div`
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  width: 100%;
  background-color: black;
`
const SPAN = styled.span`
  font-size: 3.5vmin;
  cursor: pointer;
  color: white;
  ${props =>
    props.selected &&
    css`
      color: cornflowerblue;
    `}
`
const TEXT = styled.p``

class Nav extends Component {
  constructor (props) {
    super(props)

    this.state = {
      isActive: 0
    }
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick (e) {
    console.log('Hello There')
    console.log(e.target.key)

    this.setState = {
      isActive: 1
    }
  }

  render () {
    return (
      <NAV links={this.props.links}>
        {this.props.links.map((i, ii) => (
          <SPAN
            id={ii}
            onClick={e => this.handleClick(e)}
            key={ii}
            selected={this.state.isActive === ii ? true : ''}
          >
            <TEXT>{i}</TEXT>
          </SPAN>
        ))}
      </NAV>
    )
  }
}

export default Nav
1
1. you need to stop pollute render method, move NAV & SPAN out of render method. - plat123456789
2. I don't understand the logic of your question, in your code, I only see the state controlling isActive, but you change the color base on props? how you change the props.selected value? In other word, the state is controlling isAvtive, but props controlling the color? The logic is not connected. - plat123456789
Hey. I moved the components outside the class. That's right, my logic is flawed, that's why I am posting a question for help. I only want 1 component to be active based onClick. - Ddeokbokki

1 Answers

2
votes

I figured it out by using e.currentTarget.textContent and then setting the state isSelected: e.currentTarget.textContent onClick. Code:

import React, { Component } from 'react'
import styled, { css } from 'styled-components'

const NAV = styled.div`
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  width: 100%;
  background-color: black;
`
const SPAN = styled.span`
  font-size: 3.5vmin;
  cursor: pointer;
  color: white;
  ${props =>
    props.selected &&
    css`
      color: cornflowerblue;
    `}
`
const TEXT = styled.p``

class Nav extends Component {
  constructor (props) {
    super(props)

    this.state = {
      isSelected: 'Home'
    }
    this.handleClick = this.handleClick.bind(this)
  }

  componentDidMount () {}

  handleClick (e) {
    this.setState({
      isSelected: e.currentTarget.textContent
    })
  }

  render () {
    return (
      <NAV links={this.props.links}>
        {this.props.links.map((i, ii) => (
          <SPAN
            id={ii}
            onClick={e => this.handleClick(e)}
            key={ii}
            selected={this.state.isSelected === i ? true : ''}
          >
            <TEXT>{i}</TEXT>
          </SPAN>
        ))}
      </NAV>
    )
  }
}

export default Nav