首页 > 解决方案 > Set initial active element, after resizing array of elements

问题描述

I'm kind a stuck on this. There is this standard tab menubar which receives it's data externally(array). Initial state has full array, but during work, this array gets filtered. After filter, active class should mark first element whom receives data from newly filtered array. But my logic, for some reason, marks element with index 1(letters: one) instead of zero(letters: zero) as active. Filtering is good, no objection on that part. Trouble is that this is done in React, so there are some guidelines that needs to be followed here.

Function that sets element active on click:

setActive(e){

    e.preventDefault();
    let elem = e.target;

    let len1 = elem.attributes.length;
    let obj1 = {};
    let name = null;
    let value = null;
    for(let i=0;i<len1;i++){

      let attr = elem.attributes[i];

      name = attr.name;
      value = attr.value;
      
      obj1[name] = value;
      
    }
    //Begin: Important for question asked.
    let allTabs = document.querySelectorAll(".nav-link");
    let len2 = allTabs.length;
    for(let i=0;i<len2;i++){

      if(allTabs[i]===elem){

        this.setState({
          elemIndex: i
        });
        
      }
      
    }
    //End: Important for question asked.
    this.setState(obj1);

  }

Logic that filters out elements and resets active class, it's in render method:

let elemIndex = this.state.elemIndex;
    let active =  null;
    
    let menu = this.state.menu.filter((item, i) => {

      if(this.state.access_token===null && item==="register"){
        
        return item;

      }

      if(this.state.access_token===null && item==="login"){
        
        return item;

      }

      if(this.state.access_token!==null && item==="create"){
        
        return item;

      }

      if(this.state.access_token!==null && item==="show"){
        
        return item;

      }

      if(this.state.access_token!==null && item==="update"){
        
        return item;

      }

      if(this.state.access_token!==null && item==="delete"){
        
        return item;

      }

      if(this.state.access_token!==null && item==="list"){
        
        return item;

      }
      
    });
    
    let lis = menu.map((item, i) => {
      console.log((elemIndex===i || (i===0 && elemIndex===0)), elemIndex, i);
      active = elemIndex===i || (i===0 && elemIndex===0) ? " active" : "";
      
      return <li className="nav-item" key={i} id={i}>
        <a className={"nav-link" + active} data-toggle="tab" href={"menu"+(i+1)} onClick={this.setActive}>
          {item}
        </a>
      </li>;

    });

    let tabContents = menu.map((item, i) => {
      
      active = elemIndex===i || (i===0 && elemIndex===0) ? " active" : "";

      return <div id={"menu"+(i+1)} key={i} className={"container tab-pane" + active}><br/>
        
        {item==="register" ? <Register register={this.register}/> : null}

        {item==="login" ? <Login login={this.login}/> : null}

        {this.state.access_token!==null && item==="create" ? <CreatePost createPost={this.createPost}/> : null}

        {this.state.access_token!==null && item==="show" && this.state.posts!==null ? <ShowPost onChange={this.onChange} posts={this.state.posts} post={this.state.post}/> : null}

        {this.state.access_token!==null && item==="list" && this.state.posts!==null ? <ListPosts posts={this.state.posts}/> : null}

        {this.state.access_token!==null && item==="update" && this.state.posts!==null ? <UpdatePost onChange={this.onChange} updatePost={this.updatePost} posts={this.state.posts} post={this.state.post}/> : null}

        {this.state.access_token!==null && item==="delete" && this.state.posts!==null ? <DeletePost onChange={this.onChange} updatePost={this.deletePost} posts={this.state.posts} post={this.state.post}/> : null}

      </div>;

    });

Other methods called are of no concern since they don't have anything to do with setting active class.

标签: arraysreactjs

解决方案


弄清楚了。

首先,我将过滤设置为一个单独的函数和单独的属性以包含过滤后的数组,其次我设置活动元素的逻辑很好,所以那里没有变化。第三,我进行了评估,以便当过滤后的数组不为空时,用于映射所有标签栏元素。

过滤方法:

filterize(){
    
    let menu = this.state.menu.filter((item, i) => {
      
      let access_token = this.state.access_token;
      if(access_token===null && item==="register"){
        
        return item;

      }

      if(access_token===null && item==="login"){
        
        return item;

      }

      if(access_token!==null && item==="create"){
        
        return item;

      }

      if(access_token!==null && item==="show"){
        
        return item;

      }

      if(access_token!==null && item==="update"){
        
        return item;

      }

      if(access_token!==null && item==="delete"){
        
        return item;

      }

      if(access_token!==null && item==="list"){
        
        return item;

      }
      
    });

    this.setState({
      filteredMenu: [...menu],
      elemIndex: 0
    });
    
  }

  componentDidMount(){//This needs to be since extracted logic isn't in render anymore.
    this.filterize();
  }

在渲染方法中:

let elemIndex = this.state.elemIndex;
    let active =  null;
    
    let lis = this.state.filteredMenu ? this.state.filteredMenu.map((item, i) => {
      
      active = elemIndex===i || (i===0 && elemIndex===0) ? " active" : "";
      
      return <li className="nav-item" key={i} id={i}>
        <a className={"nav-link" + active} data-toggle="tab" href={"menu"+(i+1)} onClick={this.setActive}>
          {item}
        </a>
      </li>;

    }) : this.state.menu.map((item, i) => {
      
      active = elemIndex===i || (i===0 && elemIndex===0) ? " active" : "";
      
      return <li className="nav-item" key={i} id={i}>
        <a className={"nav-link" + active} data-toggle="tab" href={"menu"+(i+1)} onClick={this.setActive}>
          {item}
        </a>
      </li>;

    });

    let tabContents = this.state.filteredMenu ? this.state.filteredMenu.map((item, i) => {
      
      active = elemIndex===i || (i===0 && elemIndex===0) ? " active" : "";

      return <div id={"menu"+(i+1)} key={i} className={"container tab-pane" + active}><br/>
        
        {item==="register" ? <Register register={this.register}/> : null}

        {item==="login" ? <Login login={this.login}/> : null}

        {this.state.access_token!==null && item==="create" ? <CreatePost createPost={this.createPost}/> : null}

        {this.state.access_token!==null && item==="show" && this.state.posts!==null ? <ShowPost onChange={this.onChange} posts={this.state.posts} post={this.state.post}/> : null}

        {this.state.access_token!==null && item==="list" && this.state.posts!==null ? <ListPosts posts={this.state.posts}/> : null}

        {this.state.access_token!==null && item==="update" && this.state.posts!==null ? <UpdatePost onChange={this.onChange} updatePost={this.updatePost} posts={this.state.posts} post={this.state.post}/> : null}

        {this.state.access_token!==null && item==="delete" && this.state.posts!==null ? <DeletePost onChange={this.onChange} updatePost={this.deletePost} posts={this.state.posts} post={this.state.post}/> : null}

      </div>;

    }) : this.state.menu.map((item, i) => {
      
      active = elemIndex===i || (i===0 && elemIndex===0) ? " active" : "";

      return <div id={"menu"+(i+1)} key={i} className={"container tab-pane" + active}><br/>
        
        {item==="register" ? <Register register={this.register}/> : null}

        {item==="login" ? <Login login={this.login}/> : null}

        {this.state.access_token!==null && item==="create" ? <CreatePost createPost={this.createPost}/> : null}

        {this.state.access_token!==null && item==="show" && this.state.posts!==null ? <ShowPost onChange={this.onChange} posts={this.state.posts} post={this.state.post}/> : null}

        {this.state.access_token!==null && item==="list" && this.state.posts!==null ? <ListPosts posts={this.state.posts}/> : null}

        {this.state.access_token!==null && item==="update" && this.state.posts!==null ? <UpdatePost onChange={this.onChange} updatePost={this.updatePost} posts={this.state.posts} post={this.state.post}/> : null}

        {this.state.access_token!==null && item==="delete" && this.state.posts!==null ? <DeletePost onChange={this.onChange} updatePost={this.deletePost} posts={this.state.posts} post={this.state.post}/> : null}

      </div>;

    });

不确定这些东西是否有更短的代码,但至少它尊重指南。


推荐阅读