Update sibling state based on another clicked sibl

2019-05-06 16:05发布

Good afternoon,

I am having trouble changing the state of components which are siblings. Basically they look like this:

<Navigation>
  <NavEndpt /> About <--- no
  <NavEndpt /> Blog
  <NavEndpt /> Projects
</Navigation>

Each <NavEndpt /> is a link that routes to a different 'page' or route on my website unless it is the first one listed, "About". About I want to be a drop down/lightbox feature something pretty to show off my CSS knowledge. So when one of the links is clicked I want it to go where I want; additionally, I'd like it to reflect which link is currently "active" (or not) by both changing it's state.active to true or false and adding an additional class active for CSS purposes. I want to new "active" class to only be present on a <NavEndpt /> that's state.active is true.

Yet everything I have tried so far hasn't worked and I've been at this for two days. I'd appreciate someone who is more experienced with React to show me how to accomplish this.

Here is what I am working with:

var MasterLayout = React.createClass({
  mixins: [History],

  render: function(){
      var childrenWithProps = React.Children.map(this.props.children,
            (child) => React.cloneElement(child, {
                doSomething: this.doSomething
            })
          );

    return(

        <div id="container">
          <Navigation activeRoute={this.props.location.pathname} />
          <div id="content">
            {childrenWithProps}
          </div>
        </div>
      )

  }
});

var Navigation = React.createClass({
    getInitialState: function(){
      var endpoints = require("./data/naviEnd.js");
      return {
        endpoints: endpoints,
        activeRoute: this.props.activeRoute
      }           
    },
renderEndpoints: function(key){
      var endpointDetails = this.state.endpoints[key];

      return(
        <NavEndpt id={endpointDetails.id} key={endpointDetails.title} url={endpointDetails.url} title={endpointDetails.title}/>
        )

    },

    render: function(){


      return(
          <div id="navigation">
              {Object.keys(this.state.endpoints).map(this.renderEndpoints)}
          </div>
        )
      }
    });

// Created child not a this.props.child of <Navigation /> component 
        // as pointed out by @BenHare

        var NavEndpt = React.createClass({

          handleClick: function(){

            this.setState({
              active: true
            })

          },
          render: function(){

            return (
              <div onClick={this.handleClick} className="navLink" id={this.props.id}>
                <Link id={this.props.id + "-link"} to={this.props.url}>{this.props.title}</Link>
              </div>
              )
          }
        })

Currently this only changes creates and set states for each <NavEndpt /> I tried to make this mess as clean as possible for Stack Overflow.

The best fix I have come up with so far uses a lot of DOM selection and hardcoded if/else statements. It also doesn't light up my "About" component because it doesn't have a url property. That's significant because I have the below solution tied up to the pathname of my entire layout component.

var MasterLayout = React.createClass({
  mixins: [History],

  render: function(){
      var childrenWithProps = React.Children.map(this.props.children,
            (child) => React.cloneElement(child, {
                doSomething: this.doSomething
            })
          );
return(

    <div id="container">
      <Navigation activeRoute={this.props.location.pathname} />
      <div id="content">
        {childrenWithProps}
      </div>
    </div>
  )

}

}); 


  // This is the parent component that sits on the side or the top depending on the
  // broswer size, contains components NavEndpt
  var Navigation = React.createClass({
    getInitialState: function(){
      var endpoints = require("./data/naviEnd.js");
      return {
        endpoints: endpoints,
        activeRoute: this.props.activeRoute
      }           
    },
// Always makes the website's initial view the home route
    componentDidMount: function(){
        var cover = document.getElementById("cover");
        var projects = document.getElementById("projects");
        var about = document.getElementById("about");

        var active = this.props.activeRoute

        this.setActive();
    },
// resets the hard coded CSS class
    resetClasses: function(){
      var active = this.props.activeRoute

      var cover = document.getElementById("cover");
      var projects = document.getElementById("projects");
      var about = document.getElementById("about");    

          cover.className = "navLink";
          projects.className = "navLink";
          about.className = "navLink";
    },
// checks pathname of <MasterLayout/>
// also somehow makes it so a refresh does not
// return you to "/"
    setActive: function(){
      var active = this.props.activeRoute

      var cover = document.getElementById("cover");
      var projects = document.getElementById("projects");
      var about = document.getElementById("about");

        if (active === "/"){

        cover.className += " active";
      } else if (active === "/projects"){

        projects.className += " active"
      } else if (active === "/about"){
        about.className += " active"
      }
},
// listens for updates, resets active first and sets it
componentDidUpdate: function(){

  this.resetClasses();
  this.setActive();

},

renderEndpoints: function(key){
  var endpointDetails = this.state.endpoints[key];

  return(
    <NavEndpt id={endpointDetails.id} key={endpointDetails.title} url={endpointDetails.url} title={endpointDetails.title}/>
    )

},

render: function(){


  return(
      <div id="navigation">
          {Object.keys(this.state.endpoints).map(this.renderEndpoints)}
      </div>
    )
  }
});



    var NavEndpt = React.createClass({

      handleClick: function(){

        this.setState({
          active: true
        })

      },
      render: function(){

        return (
          <div onClick={this.handleClick} className="navLink" id={this.props.id}>
            <Link id={this.props.id + "-link"} to={this.props.url}>{this.props.title}</Link>
          </div>
          )
      }
    })

0条回答
登录 后发表回答