Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How do I keep correct indexing while dynamically rendering React components?

I’m trying to make a dynamic React loader similar to this StackOverflow post. I am having a couple of issues, but the one I would like help with is the indexing. I have a string of component names and when the element renders it loops through all of the componentNames in the list and renders them in that order with an index. Another component is used a simple component wrapper that provides buttons for moving the component up or down.

When you click the down button on component 3 it swaps with component 4 but the indexing doesn’t change.

enter image description here

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Any pointers are much appreciated.

Here is my simplified code:

import React from 'react';

function H1(props){return <h1>H1-{props.index}</h1>}
function H2(props){return <h2>H2-{props.index}</h2>}
function H3(props){return <h3>H3-{props.index}</h3>}

export default class DynamicPageTest extends React.Component {
    constructor(props) {
        super(props);

        this.componentMapping = {
            H1:H1,
            H2:H2,
            H3:H3,
          };
 
        this.state = {
            componentNames: ["H1","H2","H3","H2","H3"]
        };
    }
 
    moveComponentUp(index){
        this.swapComponents(index,index-1)
    }
    moveComponentDown(index){
        this.swapComponents(index,index+1)
    }
 
    swapComponents(indexA,indexB){
        let newComponentNames = this.state.componentNames.slice();
        let temp = this.state.componentNames[indexB];
        newComponentNames[indexB] = newComponentNames[indexA];
        newComponentNames[indexA] = temp;
 
        this.setState({componentNames: newComponentNames});
        alert(newComponentNames)
    }

    render() {

        let pageComponents = []

        this.state.componentNames.forEach((componentName, index) => {
                let callbacks = {
                    moveComponentUp: ()=>{this.moveComponentUp(index)},
                    moveComponentDown: ()=>{this.moveComponentDown(index)} 
                               }
                const Component = this.componentMapping[componentName];

                let newComponent = <ComponentWrapper key ={`${componentName}`} index = {index} componentCount = {this.state.componentNames.length} callbacks = {callbacks}>
                                        <Component index = {index}/>
                                    </ComponentWrapper>

                pageComponents.push(newComponent)
        });
 
        return (
            <div >
                {pageComponents}
            </div>
        );
    }
  }
 
class ComponentWrapper extends React.Component {
    constructor(props) {
        super(props);
        this.children = props.children;

        this.state = {
            index:props.index,
            callbacks: props.callbacks,
            componentCount:props.componentCount
        };
      } 

    render() {

    return ( 
        
        <div style = {{display: "flex",  flexDirection: "column", border:"1px solid black",margin:"10px 0px"}}>
            <div style={{display: "flex",  flexDirection: "row", position:"relative"}}>
                {this.state.index}{this.children}
                <div style={{display: "flex",  flexDirection: "column",position: "absolute", right: "0"}}>
                    <div style={{height:"100%",display:"flex",flexDirection:"column",justifyContent:"baseline"}}>
                        {this.state.index != 0 && <button onClick = {this.state.callbacks.moveComponentUp}>Move Up</button>}
                        {this.state.index != this.state.componentCount - 1 && <button onClick = {this.state.callbacks.moveComponentDown}>Move Down</button>}
                    </div>
                </div>
            </div>
        </div>
    )
    };
}

>Solution :

This is because you are setting this.state.index from the props.index in the constructor. This is not a mistake per se. But, when the component is rerendered, the state.index is set once and not updated anymore.
If you want it to be updated, use the index from the props directly.

...
    {this.props.index}{this.children}
                <div style={{display: "flex",  flexDirection: "column",position: "absolute", right: "0"}}>
                    <div style={{height:"100%",display:"flex",flexDirection:"column",justifyContent:"baseline"}}>
                        {this.props.index != 0 && <button onClick = {this.state.callbacks.moveComponentUp}>Move Up</button>}
                        {this.props.index != this.state.componentCount - 1 && <button onClick = {this.state.callbacks.moveComponentDown}>Move Down</button>}
                    </div>
                </div>
    ...
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading