简体   繁体   中英

How to add attribute to HTML tag passed in props- before render?

I have some code that takes an array of JSX as props. The component is supposed to ensure that all JSX is rendered in the order they appear in the array. In order to do this, all of my components have an optional onLoad function they can take as a prop. When I initially create the array of JSX in a parent component, this function isn't being added, so that I don't have to write the same function in all of these different parent classes. So I pass them to my component that handles the load order, but it needs a way to add the onLoad attribute to everything in the array.

I have tried mapping through the array and using child.setAttribute on each element, but I get the error: setAttribute is not a function

I have also tried child.onLoad = this.childDidLoad which resulted in the error: Cannot add property onLoad, object is not extensible

I have tried spreading, which you should see below. This doesn't throw errors, but appears to never add the attribute, as that section of code is never reached.

class StandardPage extends Component {
  static propTypes = {
    children: PropTypes.array.isRequired, // All child components to render
  };

  state = {
    childrenLoaded: 0, // Number of children loaded
  };

  /**
   * When this method is called, a child has updated.
   * Take previous value of number of children loaded, and add one.
   * Store as new value in state
   */
  childDidLoad() {
    const {childrenLoaded} = this.state;

    this.setState({
      childrenLoaded: childrenLoaded + 1,
    });
  }

  /**
   * Slice children array to only return those that have loaded, plus one.
   * THIS CONTAINS THE PROBLEM!!!
   * @return {array} JSX array
   */
  getLoaded() {
    const {childrenLoaded} = this.state;
    const {children} = this.props;

    this.childDidLoad = this.childDidLoad.bind(this);
    const loaded = children.slice(0, childrenLoaded + 1);

    return loaded.map((child) => {
      return {
        ...child, // THIS IS THE PROBLEM SPOT
        onLoad: this.childDidLoad,
      };
    });
  }

  /**
   * Visual component
   * @return {jsx}
   */
  render() {
    const components = this.getLoaded();

    return (
      <div className="page">
        <Nav>
          {components}
        </Nav>
      </div>
    );
  }
}

example use:

class ExamplePage extends Component {
  state = {
    children: [
      <Section
            key="origin"
            restEndpoint="origin"
            id={originID}
            bgColor={(isYellow) ? 'yellow' : 'white'}
            txtJustify={true}
          />,
      <Section
            key="funFacts"
            restEndpoint="funfacts"
            id={funFactID}
            bgColor={(isYellow) ? 'yellow' : 'white'}
            txtJustify={true}
          />
    ],
  };

  /**
   * Visual component
   * @return {jsx}
   */
  render() {
    const {children} = this.state;

    return (
      <StandardPage children={children} />
    );
  }
}

Right now, the first child component gets displayed, and no others, as the childDidLoad method is never getting called.

return loaded.map((child) => {
    return React.cloneElement(child, { onLoad: this.childDidLoad });
});

This may work for you to pass the method as a prop to your Component. I gonna setup a test on my local machine for further investigations if it doesnt help. greetz

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM