简体   繁体   中英

How would I sort a prop of an array of objects nondestructively Reactjs?

So I am trying to sort alphabetically an array of objects nondestructively by using state, so I can also return the array back to its original arrangement. I've tried quite a few ways of copying the original array into a new array to sort: JSON methods to carry a deep copy of this.props.getDaycare.toddlers :

 constructor(){
        super()
        this.state = {
            newArray: []
        }
        
    }

    sort = () => {
        let initialArray = this.props.getDaycare.toddlers
        let copiedInitialArray = JSON.parse(JSON.stringify(initialArray));
        console.log(copiedInitialArray)
        this.setState({
                newArray: copiedInitialArray.sort((t,u) =>{
                if (t.name < u.name) {return -1;}
                if (t.name > u.name) {return 1;}
                return 0;
               })
        })
    
    }

That didn't seem to work. It did not update the DOM at all, but it did in the console (alphabetically) when I clicked the sort button

0: {id: 84, name: 'Jared Leno', birthday: '2019-09-02', contact: 'Poppy Roberts', phone: 7605551919, …}
1: {id: 88, name: 'Massimo Gandolfini', birthday: '2019-01-06', contact: 'Poppy Roberts', phone: 7605551919, …}
2: {id: 87, name: 'Rosie Perez', birthday: '2018-12-22', contact: 'Poppy Roberts', phone: 7605559091, …}
3: {id: 80, name: 'Samantha Madison', birthday: '2019-01-06', contact: 'Olusoji Akinremi', phone: 7605551919, …}
4: {id: 90, name: 'Sara Waters', birthday: '2018-12-22', contact: 'Jessica Smith', phone: 7605559091, …}
5: {id: 83, name: 'Serena Williams', birthday: '2019-01-06', contact: 'Sara Reynolds', phone: 7605551919, …}
length: 6
[[Prototype]]: Array(0)

I've tried the shallow copying methods as well such as spread , slice , from . Noting but the same result of not updating the DOM but outputting in the console. I've looked everywhere online for this specific issue and I haven't seen any example showing how to effectively deep copy an array of objects for sorting. All the examples were destructive to the original array.

I'm wondering is there any way at all? please help.

  1. To copy a JS Array, you can use Array#slice method. You don't need a deep copy since the values in React are supposed to be immutable.
  2. I believe your problem is elsewhere. My guess is that you're mixing up props and state, which causes to not update DOM as you'd like it to. To know for sure, you'd have to provide the render method.
  3. The recommended way in this case would be to not modify the state when you want to sort, but to sort elements during the render phase/function.

Like this:

const cmp = (a, b) => (a > b) - (a < b);
class SortedList extends React.Component {
    constructor(props) {
    super(props)
    this.state = {
        sort: { field: 'name', descending: false },
    };
  }
  render() {
    const { field, descending } = this.state.sort;
    const mul = descending ? -1 : 1;
    const items = this.props.items.slice();
    items.sort((a, b) => mul * cmp(a[field], b[field]));
    return (
      <ul>
        {items.map(({id, name}) => <li key={id}>{name}</li>)}
      </ul>
    );
  }
}

In react, you should think of what renders as a function of props and state .

So there is no need to set the sorted array to state, only the sortType , sortDirection , and other factors that might play a part in how the list is sorted.

const List = ({ data }) => {
  const [sortType, setSortType] = useState("name"); //name | birthday | contact
  const [sortDirection, setSortDirection] = useState("ASC"); //ASC | DESC

  const sortBy = (a, b) => {
    if (sortDirection === "ASC") {
      return (a[sortType] > b[sortType]) - (a[sortType] < b[sortType]);
    }
    return (b[sortType] > a[sortType]) - (b[sortType] < a[sortType]);
  };

  const handleChange = (e) => {
    const { value, name } = e.target;
    if (name === "sortType") {
      setSortType(value);
    }
    if (name === "sortDirection") {
      setSortDirection(value);
    }
  };

  return (
    <div>
      <h2>List</h2>
      <form onChange={handleChange}>
        <fieldset>
          <legend>Sort by</legend>
          <label>
            Name
            <input
              type="radio"
              name="sortType"
              value="name"
              defaultChecked={true}
            />
          </label>
          <label>
            Birthday
            <input type="radio" name="sortType" value="birthday" />
          </label>
          <label>
            Contact
            <input type="radio" name="sortType" value="contact" />
          </label>
        </fieldset>
        <fieldset>
          <legend>Direction</legend>
          <label>
            Ascending
            <input
              type="radio"
              name="sortDirection"
              value="ASC"
              defaultChecked={true}
            />
          </label>
          <label>
            Descending
            <input type="radio" name="sortDirection" value="DESC" />
          </label>
        </fieldset>
      </form>

      <ul>
        {data.sort(sortBy).map((d, i) => (
          <ListItem data={d} key={i} />
        ))}
      </ul>
    </div>
  );
};

编辑 little-dream-6nig5

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