一次更新许多孩子的状态

时间:2019-04-21 07:24:50

标签: reactjs

我试图通过打开/关闭用于创建那些项目的技能组件来控制GalleryItem组件的可见性。我想要: 如果没有技能切换,则显示全部 如果切换了一项或多项技能,则仅显示使用该技能的GalleryItems

所选技能存储在Portfolio组件的state.portfolioTypes中-可以按预期工作。

我只是不知道如何从我的Skill组件的点击处理程序中调用每个GalleryItem组件上的updateDisplay方法。

如果有人可以帮助我,那我就飞了!谢谢。

我尝试将GalleryItem组件推到处于父状态的数组中,以便在切换技能时可以遍历该数组,但是尽管在将数组登录到控制台时看到了组件对象,但它们并没有在用户界面中呈现-而是呈现数字13-24(不知道为什么...)

resumeData.skills如下:

skills: ["Branding", "Design", "UX", "Marketing", "Print", "Javascript", "HTML", "Grunt", "JQuery", "LessCSS", "Sketch", "Photoshop", "Illustrator", "Bootstrap"]

传递给GalleryItem类的项目如下:

{
    imagePath: "images/portfolio/monster.png",
    name: "Monster.com",
    description: "Web design, UI Development and Art Direction",
    modalImagePath: "images/portfolio/lrg/monster.png",
    modalName: "Web design, UI Development and Art Direction",
    modalDescription: "Working for one of the internet's biggest brands, I developed UI for internal incubator projects, components of the global web application and helped with the full UI redesign of the job seeker experience.",
    modalCategories: ["Branding", "Design", "UX", "Photoshop", "Illustrator"],
    url: "http://www.monster.com"
}

我的投资组合类,其中包含技能类和GalleryItem类: (我删除了一些与此问题无关的代码)

import React, { Component } from 'react';
export default class Portfolio extends Component {
      constructor(props){
          super(props);
          this.state = {
              portfolioTypes: [],
              galleryItems: []
          }
          this.togglePortfolioItems = this.togglePortfolioItems.bind(this);
      }

      togglePortfolioItems(item){
          //render only portfolio items with selected tags
          console.log("togglePortfolioItems", item);
          let portfolioTypes = this.state.portfolioTypes;
          if(!item.isToggleOn){
              portfolioTypes.push(item.type);
          }else{
              portfolioTypes.splice(portfolioTypes.indexOf(item.type), 1);
          }

          this.setState({portfolioTypes: portfolioTypes});

          console.log(this.state.portfolioTypes, portfolioTypes);
      }

      render() {
        let resumeData = this.props.resumeData;
        let togglePortfolioItems = this.togglePortfolioItems;
        let portfolioTypes = this.state.portfolioTypes;
        let galleryItems = this.state.galleryItems;
        return (
            <React.Fragment>
            <section id="portfolio">
                <div className="row">
                  <div className="twelve columns collapsed">
                    <h1>Check Out Some of My Works.</h1>
                    <div className="skillToggles">
                        {resumeData.skills.map((item,index) => (
                            <Skill 
                                skillName={item}
                                togglePortfolioItems={togglePortfolioItems}
                                galleryItems={galleryItems}
                            />
                        ))}
                    </div>
                    {/* portfolio-wrapper */}
                    <div id="portfolio-wrapper" className="bgrid-quarters s-bgrid-thirds cf">
                        {resumeData.portfolio.map((item,index) => (
                            galleryItems.push(<GalleryItem 
                                item={item}
                                index={index}
                                portfolioTypes={portfolioTypes}
                            />)
                        ))}
                    </div> {/* portfolio-wrapper end */}
                  </div> {/* twelve columns end */}
                </div> {/* row End */}
              </section> {/* Portfolio Section End*/}
          </React.Fragment>
        );

        this.setState({galleryItems: galleryItems});
      }
}

class Skill extends Component {
  constructor(props) {
    super(props);
    this.state = {
        isToggleOn: false,
        type: props.skillName.toLowerCase()
    };

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e) {
    e.preventDefault();
    this.setState(state => ({
      isToggleOn: !state.isToggleOn
    }));

    this.props.togglePortfolioItems(this.state);

    let galleryItems = this.props.galleryItems;
    //loop through all galleryItems and set the display of each
    galleryItems.map(galleryItem =>(
        console.log(galleryItem);
        //I would like to fire updateDisplay on galleryItem here
    ));
  }

  render() {
    let skillName = this.props.skillName;
    let skillNameId = skillName.toLowerCase();
    return (
        <React.Fragment>
        <a href="" className={"skill "+(this.state.isToggleOn ? 'on' : 'off')} onClick={this.handleClick}>
            {skillName}
        </a> {/* Skill Section End*/}
      </React.Fragment>
    );
  }
}

class GalleryItem extends Component{
    constructor(props) {
        super(props);
        let portfolioTypes = this.props.portfolioTypes;
        var displayed = true;

        this.state = {
            displayed: displayed
        };
    }

    updateDisplay(){
        let portfolioTypes = this.state.portfolioTypes;
        let displayed = false;
        if(portfolioTypes.length === 0){
            displayed = true;
        }else{
            for(var x=0; x<portfolioTypes.length; x++){
                let cat = portfolioTypes[x];
                if(portfolioTypes.indexOf(cat) > -1){
                    displayed = true;
                }
            };
        }

        this.setState({displayed: displayed});
    }

    render() {
        let item = this.props.item;
        let index = this.props.index;

        return (
            <React.Fragment>
            <div className={"columns portfolio-item "+(this.state.displayed ? "" : "hide ")+item.modalCategories.sort().join(" ").toLowerCase()}>
                <div className="item-wrap">
                  <a href={"#modal-0"+index} title={item.name}>
                    <img alt src={item.imagePath} />
                    <div className="overlay">
                      <div className="portfolio-item-meta">
                        <h5>{item.name}</h5>
                        <p>{item.description}</p>
                      </div>
                    </div>
                    <div className="link-icon"><i className="icon-plus" /></div>
                  </a>
                </div>
              </div>
          </React.Fragment>
        );
      }
}

切换技能时,我希望图库更新为仅显示使用所选技能的GalleryItem。

也许您也可以建议对我的方法进行改进,因为可能有更好/更容易/更健壮的方法来实现这一目标。

2 个答案:

答案 0 :(得分:1)

  1. 更改这样的updateDisplay功能
updateDisplay(){
        let portfolioTypes = this.props.portfolioTypes;
        let displayed = false;
        if(portfolioTypes.length === 0){
            displayed = true;
        }else{
            for(var x=0; x<portfolioTypes.length; x++){
                let cat = portfolioTypes[x];
                if(portfolioTypes.indexOf(cat) > -1){
                    displayed = true;
                }
            };
        }

        return displayed;
    }
  1. 然后在render中定义一个变量 var displayed = this.updateDisplay()
  2. 使用此变量代替this.state.displayed

答案 1 :(得分:0)

import React, { Component } from 'react';
export default class Portfolio extends Component {
      constructor(props){
          super(props);
          this.state = {
              portfolioTypes: []
          }
          this.togglePortfolioItems = this.togglePortfolioItems.bind(this);
      }

      togglePortfolioItems(item){
          //render only portfolio items with selected tags
          console.log("togglePortfolioItems", item);
          let portfolioTypes = this.state.portfolioTypes;
          if(!item.isToggleOn){
              portfolioTypes.push(item.type);
          }else{
              portfolioTypes.splice(portfolioTypes.indexOf(item.type), 1);
          }

          this.setState({portfolioTypes: portfolioTypes});

          console.log(this.state.portfolioTypes, portfolioTypes);
      }

      render() {
        let resumeData = this.props.resumeData;
        let togglePortfolioItems = this.togglePortfolioItems;
        let portfolioTypes = this.state.portfolioTypes;
        return (
            <React.Fragment>
            <section id="portfolio">
                <div className="row">
                  <div className="twelve columns collapsed">
                    <h1>Check Out Some of My Works.</h1>
                    <div className="skillToggles">
                        {resumeData.skills.map((item,index) => (
                            <Skill 
                                skillName={item}
                                key={index}
                                togglePortfolioItems={togglePortfolioItems}
                            />
                        ))}
                    </div>
                    {/* portfolio-wrapper */}
                    <div id="portfolio-wrapper" className="bgrid-quarters s-bgrid-thirds cf">
                        {resumeData.portfolio.map((item,index) => (
                            <GalleryItem 
                                item={item}
                                index={index}
                                key={index}
                                portfolioTypes={portfolioTypes}
                            />
                        ))}
                    </div> {/* portfolio-wrapper end */}
                  </div> {/* twelve columns end */}
                </div> {/* row End */}
              </section> {/* Portfolio Section End*/}
          </React.Fragment>
        );
      }
}

class Skill extends Component {
  constructor(props) {
    super(props);
    this.state = {
        isToggleOn: false,
        type: props.skillName
    };

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e) {
    e.preventDefault();
    this.setState(state => ({
      isToggleOn: !state.isToggleOn
    }));

    this.props.togglePortfolioItems(this.state);
  }

  render() {
    let skillName = this.props.skillName;
    return (
        <React.Fragment>
        <a href="#" className={"skill "+(this.state.isToggleOn ? 'on' : 'off')} onClick={this.handleClick}>
            {skillName}
        </a> {/* Skill Section End*/}
      </React.Fragment>
    );
  }
}

class GalleryItem extends Component{
    constructor(props) {
        super(props);
        let portfolioTypes = this.props.portfolioTypes;
    }

    updateDisplay(){
        console.log("updateDisplay");
        let portfolioTypes = this.props.portfolioTypes;
        let item = this.props.item;
        let displayed = false;
        if(portfolioTypes.length === 0){
            displayed = true;
        }else{
            for(var x=0; x<portfolioTypes.length; x++){
                let cat = portfolioTypes[x];
                if(item.modalCategories.indexOf(cat) > -1){
                    displayed = true;
                }
            };
        }

        return displayed;
    }

    render() {
        let item = this.props.item;
        let index = this.props.index;
        var displayed = this.updateDisplay();

        return (
            <React.Fragment>
            <div className={"columns portfolio-item "+(displayed ? "" : "hide ")+item.modalCategories.sort().join(" ")}>
                <div className="item-wrap">
                  <a href={"#modal-0"+index} title={item.name}>
                    <img alt="Gallery Image" src={item.imagePath} />
                    <div className="overlay">
                      <div className="portfolio-item-meta">
                        <h5>{item.name}</h5>
                        <p>{item.description}</p>
                      </div>
                    </div>
                    <div className="link-icon"><i className="icon-plus" /></div>
                  </a>
                </div>
              </div>
          </React.Fragment>
        );
      }
}