ltdev
ltdev

Reputation: 4477

React on click event order array of data passing in the component

I'm new to React and I'd like some help please. I'm having a button and a component inside my app.js which is the main file

import React from 'react'

const App = () =>  {

  const {data, loading, error} = useQuery(GET_DATA, {
    variables: {...}
  })

  console.log(data)

  state = {
    clickSort: false
  }   

  let clickSort = () => {
    this.setState({
      clickSort: true
    })
  }

  return (
    <div className="myApp">
          <button onClick="{this.clickSort}">Click Me</button>

        <div className="myClass">
          <FooComponent fooData={data} clickSort={this.state.clickSort} />
        </div>
</div>
  )
}

What I want to do is when I click the button to sort the array of data I'm rendering in my component in a desc order. I was thinking of passing another parameter like a flag in the component, but I'm not sure how can I do this

Upvotes: 1

Views: 778

Answers (3)

Yevhen Horbunkov
Yevhen Horbunkov

Reputation: 15530

If both of your components (<Button /> and <List />) are wrapped within common parent (<Parent />) you may employ the concept, known as lifting state up

Essentially, it is binding event handler within one of the child component's props (onSort() of <Button />) to the callback within parent (handleSort() of <Parent />), as well as binding dependent child prop (isSorted of <List />) to the state variable of common parent (sorted of <Parent />).

With that, you simply keep track of sorted flag within parent state (using useState() hook) and once handleSort() is triggered, it modifies that flag and consequent re-render of dependent components (<List />) takes place:

const { render } = ReactDOM,
      { useState } = React
      
const sampleData = ['itemC', 'itemA', 'itemD', 'itemB']      
      
const Button = ({onSort}) => <button onClick={onSort}>Sort it</button>

const List = ({listData, isSorted}) => { 
  const listToRender = isSorted ? listData.sort((a,b) => b > a ? 1 : -1) : listData
  return (
    <ul>
      {listToRender.map((li,key) => <li {...{key}}>{li}</li>)}
    </ul>
  )
}

const Parent = () => {
  const [sorted, setSorted] = useState(false),
        handleSort = () => setSorted(true)
  return (
    <div>
      <Button onSort={handleSort} />
      <List listData={sampleData} isSorted={sorted} />
    </div>
  )
}

render (
  <Parent />,
  document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>

Upvotes: 1

Ricardo Pierre-Louis
Ricardo Pierre-Louis

Reputation: 184

Pass the data from the state into FooComponent and write a function that sorts the data in that state. The data will instantly be updated in the child component once the state has updated in the parent component because the child component will rerender once it's noticed that the data in the parent component doesn't match the data that it previously received. Below is an example.

import React from 'react'

const FooComponent = ({ fooData }) => (
  <div>
    {fooData}
  </div>
)

export default class Home extends React.Component {

  constructor(props){
    super(props);
    this.state = {
      data: [1, 4, 2, 3]
    }
  }

  sortData() {
    const { data } = this.state;
    this.setState({
      data: data.sort((a, b) => b - a),
    })
  }

  render(){
    const { data } = this.state;
    return (
      <div>
        <button id="myBtn" onClick={() => this.sortData()}>Click Me</button>
        <div className="myClass">
          <FooComponent fooData={data} />
        </div>
      </div>
    )
  }
}

Upvotes: 0

tmdesigned
tmdesigned

Reputation: 2254

It looks from your question that you want to let a child component (FooComponent) know that the button has been clicked so that it can process (sort) the data it has received.

There are a lot of approaches to this. For instance, you could pass a boolean property to the child component that is a flag for it to do the sorting. So the parent component tracks when the button has been clicked, and the child component just observes this (perhaps in componentDidUpdate).

This would change slightly if you are using functional components, rather than class based components, but it gives you an idea.

state = {
   requestSort: false
}   

requestSort = () => {
    this.setState({
        requestSort: true
    }
}

render() {
        return (
          <>
            <button id="myBtn" onClick={this.requestSort}>Click Me</button>

            <div className="myClass">
                <FooComponent requestSort={this.state.requestSort} fooData={data} />
            </div>
          </>
        )
}

Alternatively, since the data is being passed to the child component as well, you could have the parent sort it when it is clicked. It depends on if you are doing anything else with the data (i.e. is only FooComponent the one that should have the sorted copy of the data or not).

Upvotes: 0

Related Questions