Sahar
Sahar

Reputation: 111

How to sort data in ReactJs

I have Items data which I am attempting to display array values sorted by cost field in costtable array when roomname is Double and type is 2.Here is my code:

Json:

    {
        "index": 1,
        "id": "5e3961face022d16a03b1de9_1023632_1004876",
        "costtable": [
            {
                "roomname": "Single",
                "room_id": "1023632_479490,1004876_385485",
                "family": [
                    {
                        "title": "adult 1",
                        "cost": 3.7568000,
                        "unit": "10",
                        "type": "2"
                    }
                ]
            }
        ]
    },
    {
        "index": 2,
        "id": "5e3961face022d16a03b1de9_1088496_1005362",
        "costtable": [
            {
                "roomname": "Double",
                "room_id": "1088496_447339,1005362_415279",
                "family": [
                    {
                        "title": "adult 1",
                        "cost": 5.6868000,
                        "unit": "10",
                        "type": "2"
                    }
                ]
            }
        ]
    },
    {
        "index": 3,
        "id": "5e3961face022d16a03b1de9_1141859_1005529",
        "costtable": [
            {
                "roomname": "Single",
                "room_id": "1141859_74888,1005529_870689",
                "family": [
                    {
                        "title": "adult 1",
                        "cost": 5.9586000,
                        "unit": "10",
                        "type": "2"
                    }
                ]
            }
        ]
    }
]

Code:

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            Items: [],
            library: null,
            perPage: 20,
            currentPage: 1,
            maxPage: null,

        }
    }
    componentDidMount() {
        fetch('/json', {
            method: 'GET',
        })
            .then(response => response.text())
            .then(text => {
                let Maindata = JSON.parse(text.replace(/\'/g, '"'))
                let CostSort = Maindata.map(a => {
                    return this.renderSort(a)
                })
                Maindata.sort((a, b) => a.CostSort - b.CostSort);
                this.setState(state => ({
                    ...state,
                    Items: Maindata
                }), () => {
                    this.reorganiseLibrary()
                })
            }).catch(error => console.error(error))

    }
    reorganiseLibrary = () => {
        const { perPage, Items } = this.state;
        let library = Items;
        library = _.chunk(library, perPage);
        this.setState({
            library,
            currentPage: 1,
            maxPage: library.length === 0 ? 1 : library.length
        });
    };

    renderSort(element) {
        let indents = []
        let lenFamilies = element.costtable.length
        for (let i = 0; i < lenFamilies; i++) {
            if (element.costtable[i].roomname.indexOf('Double') > -1) {
                for (let j = 0; j < element.costtable[i].family.length; j++) {
                    if (element.costtable[i].family[j].type == 2) {
                        indents.push(element.costtable[i].family[j].cost)
                        break;
                    }
                }
                break;
            }
        }
        return (indents)

    }

    // Previous Page
    previousPage = event => {
        this.setState({
            currentPage: this.state.currentPage - 1
        });
    };
    // Next Page 
    nextPage = event => {
        this.setState({
            currentPage: this.state.currentPage + 1
        });
    };



    // handle per page
    handlePerPage = (evt) =>
        this.setState({
            perPage: evt.target.value
        }, () => this.reorganiseLibrary());

    // handle render of library
    renderLibrary = () => {
        const { library, currentPage } = this.state;
        if (!library || (library && library.length === 0)) {
            return '';
        }
        return library[currentPage - 1].map((item, i) => (
            <div className="item-list">
                {item.index}
            </div>
        ));
    };
    render() {
        const { library, currentPage, perPage, maxPage } = this.state;
        return (
            <div>
                <div className="wrapper-data">
                    {this.renderLibrary()}
                </div>
                <div class="clr"></div>
                <ul id="page-numbers">
                    <li className="nexprevPage">
                        {currentPage !== 1 && (
                            <button onClick={this.previousPage}><span className="fa-backward"></span></button>
                        )}
                    </li>
                    <li className="controlsPage active">{this.state.currentPage}</li>
                    <li className="restControls">...</li>
                    <li className="controlsPage">{this.state.maxPage}</li>
                    <li className="nexprevPage">
                        {(currentPage < maxPage) && (<button onClick={this.nextPage}><span className="fa-forward"></span></button>
                        )}
                    </li>
                </ul>
            </div>
        );
    }

}
ReactDOM.render(<App />, document.getElementById('Content'));

This code does not give me any errors but displays the values in an unsorted format. How can I sort it?

New Code

  Maindata.sort((a, b) => {
            let lenFamilies = a.costtable.length
            for (let i = 0; i < lenFamilies; i++) {
                if( a.costtable[i].roomname.indexOf('Double') > -1){
                    for (let j = 0; j < a.costtable[i].family.length; j++) {
                        if( a.costtable[i].family[j].type == 2){

                        a.costtable[i].family[j].cost- b.costtable[i].family[j].cost
                        }
                    }
                }
            }
        }

Upvotes: 0

Views: 175

Answers (2)

Hassaan Tauqir
Hassaan Tauqir

Reputation: 2722

I do not understand the exact formula that you are using to sort, but what you are doing before the sort is wrong.

In your componentDidMount

let CostSort = Maindata.map(a => { return this.renderSort(a) })

This returns an array into a variable called CostSort and does not affect MainData in any way.

However, later on you do this.

Maindata.sort((a, b) => a.CostSort - b.CostSort);

For first iteration, this will compare Maindata[0] and Maindata[1]. Note that there is no CostSort in either of the objects and hence you are performing operation of undefined - undefined which is NaN. Therefore no sorting happens.

I would suggest you use only the sort function and do your comparison between two values there.

Maindata.sort((a, b) => {
 // Do your calculation here

 if(a should be before b) {
    return -1;
  } else {
    return 1;
  }
}

P.S The convention for variable in js is camelCase and not PascalCase. So, Maindata should he mainData.

EDIT: Here is a simple sort implementation which works for the above case, you can expand on it according to your full use case.

Maindata.sort((a, b) => {
  let lenFamilies = a.costtable.length;
  for (let i = 0; i < lenFamilies; i++) {
    if (
      a.costtable[i].roomname.includes("Double") &&
      !b.costtable[i].roomname.includes("Double")
    ) {
      return -1;
    }
    if (
      !a.costtable[i].roomname.includes("Double") &&
      b.costtable[i].roomname.includes("Double")
    ) {
      return 1;
    }
    if (a.costtable[i].roomname.indexOf("Double") > -1) {
      for (let j = 0; j < a.costtable[i].family.length; j++) {
        if (a.costtable[i].family[j].type == 2) {
          a.costtable[i].family[j].cost - b.costtable[i].family[j].cost;
        }
      }
    }
  }
});

Upvotes: 1

Piotr Żak
Piotr Żak

Reputation: 2132

Omitting the algorithms (bubble, quicksort, by inserting ...). There is possible of sorting in UI context.

Your json have: title | cost | unit | type

What type of sort You need? (title is string (can eg. sort alphabetically), then cost, unit & type are number (ascending + descending)

It's will be helpfull - when in future You provide only neccessary piece of code.


Here it's ellegant minimalistic function responsible for asc/desc sorting.

Firstly it's need to pass the props(which You wan't to sort) to values state.

function App() {
  const [ascValue, setAscValue] = useState(true);
  const [values, setValues] = useState([10, 5, 12, 1, 2, 900, 602]);

  function sortValues() {
    const compare = ascValue ? (a, b) => a - b : (a, b) => b - a;
    setValues([...values].sort(compare));
  }

  useEffect(() => {
    sortValues();
  }, [ascValue]);

  return (
    <div>
      <h3>{ascValue.toString()}</h3>
      <button onClick={() => setAscValue(!ascValue)}>Toggle Asc</button>
      {values.map(v => (
        <p key={v}>{v}</p>
      ))}
    </div>
  );
}

Here is sorting by cost for your object:

let text = [{
    "index": 1,
    "id": "5e3961face022d16a03b1de9_1023632_1004876",
    "costtable": [
        {
            "roomname": "Single",
            "room_id": "1023632_479490,1004876_385485",
            "family": [
                {
                    "title": "adult 1",
                    "cost": 3.7568000,
                    "unit": "10",
                    "type": "2"
                }
            ]
        }
    ]
},
{
    "index": 2,
    "id": "5e3961face022d16a03b1de9_1088496_1005362",
    "costtable": [
        {
            "roomname": "Double",
            "room_id": "1088496_447339,1005362_415279",
            "family": [
                {
                    "title": "adult 1",
                    "cost": 5.6868000,
                    "unit": "10",
                    "type": "2"
                }
            ]
        }
    ]
},
{
    "index": 3,
    "id": "5e3961face022d16a03b1de9_1141859_1005529",
    "costtable": [
        {
            "roomname": "Single",
            "room_id": "1141859_74888,1005529_870689",
            "family": [
                {
                    "title": "adult 1",
                    "cost": 5.9586000,
                    "unit": "10",
                    "type": "2"
                }
            ]
        }
    ]
}
]

const App = () =>{

    const usersWithName = Object.keys(text).map(function(key) {
        var user = text[key];
        return user.costtable[0].family[0].cost;
      });

    let costArray = usersWithName

    const [ascValue, setAscValue] = useState(true);
    const [values, setValues] = useState(costArray);


        function sortValues() {
            const compare = ascValue ? (a, b) => a - b : (a, b) => b - a;
            setValues([...values].sort(compare));
          }


        useEffect(() => {
            sortValues();
          }, [ascValue]);




        return (
        <div>
            <h3>{ascValue.toString()}</h3>
            <button onClick={() => setAscValue(!ascValue)}>Toggle Asc</button>
            {values.map(v => (
                <p key={v}>{v}</p>
            ))}
        </div>
        );
    }

export default App;

I don't have idea of performance in this case + if in your json are more costtable & family it should iterate by [i] iterator.

Upvotes: 0

Related Questions