2015-04-08 3 views
93

Я пытаюсь найти лучший способ удалить элемент из массива в состоянии компонента. Так как я не должен изменить переменную this.state непосредственно, есть лучший способ (более кратко), чтобы удалить элемент из массива, чем то, что я здесь ?:Удаление элемента из массива в состоянии компонента

onRemovePerson: function(index) { 
    this.setState(prevState => { // pass callback in setState to avoid race condition 
     let newData = prevState.data.slice() //copy array from prevState 
     newData.splice(index, 1) // remove element 
     return {data: newData} // update state 
    }) 
    }, 

Спасибо.

обновленный

Это был обновлен для использования обратного вызова в SetState. Это должно быть сделано при обращении к текущему состоянию при его обновлении.

+0

Взгляните на ImmutableJS из Facebook, который хорошо работает с React. [link] (http://facebook.github.io/immutable-js/docs/#/) –

+6

Я не вижу ничего плохого в вашем коде. На самом деле это очень идиоматический способ сделать это. –

ответ

81

Вы можете использовать update() immutability helper from react-addons-update, что фактически делает то же самое под капотом, но то, что вы делаете, прекрасно.

this.setState(prevState => ({ 
    data: update(prevState.data, {$splice: [[index, 1]]}) 
})) 
+0

Гораздо проще, чем тот, с которым вы связались :) –

+5

'react-addons-update' теперь устарел (2016). «immutability-helper» доступен в качестве замены. https://github.com/kolodny/immutability-helper Также см. мой ответ ниже, касающийся не мутации this.state непосредственно внутри this.setState(). – pscl

79

Чистейший способ сделать это, что я видел с filter:

removeItem(index) { 
    this.setState({ 
    data: this.state.data.filter((_, i) => i !== index) 
    }); 
} 
+6

работает! не могли бы вы объяснить, для чего это _? – HussienK

+12

@HussienK '_' иногда используется для представления неиспользуемого аргумента. Здесь это текущий элемент массива. – chrisM

+1

Amazing. Я использую .filter все время, но никогда не думал использовать его в этой ситуации. : D – dakt

16

Вот способ, чтобы удалить элемент из массива в состоянии, используя ES6 распространять синтаксис.

onRemovePerson: (index) => { 
    const data = this.state.data; 
    this.setState({ 
    data: [...data.slice(0,index), ...data.slice(index+1)] 
    }); 
} 
+0

Спасибо! Это похоже на самый естественный способ сделать это. – faviouz

-3

Вот простой способ сделать это:

removeFunction(key){ 
    const data = {...this.state.data}; //Duplicate state. 
    delete data[key];     //remove Item form stateCopy. 
    this.setState({data});    //Set state as the modify one. 
} 

Надеется, что это помогает !!!

+1

Зачем это произошло? –

+0

Я скажу, что в ES6 не хватает знаний – T04435

+0

Уход за разъяснением? –

34

Я считаю ссылки this.state внутри setState() обескураживают https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

Документов рекомендуются использовать setState() с функцией обратного вызова, так что prevState передается в во время выполнения, когда происходит обновление. Так вот как это будет выглядеть:

Использование Array.prototype.filter без ES6

removeItem : function(index) { 
    this.setState(function(prevState){ 
    return { data : prevState.data.filter(function(val, i) { 
     return i !== index; 
    })}; 
    }); 
} 

Использование Array.prototype.filter с ES6 стрелками Функции

removeItem(index) { 
    this.setState((prevState) => ({ 
    data: prevState.data.filter((_, i) => i !== index) 
    })); 
} 

Использование неизменяемость-помощник

import update from 'immutability-helper' 
... 
removeItem(index) { 
    this.setState((prevState) => ({ 
    data: update(prevState.data, {$splice: [[index, 1]]}) 
    })) 
} 

Используя Spread

function removeItem(index) { 
    this.setState((prevState) => ({ 
    data: [...prevState.data.slice(0,index), ...prevState.data.slice(index+1)] 
    })) 
} 

Обратите внимание, что в каждом случае, независимо от используемого метода, this.setState() передается обратный вызов, не является объектом ссылки на старый this.state;

+3

Это правильный ответ, см. Также [Сила не мутирующих данных] (https://facebook.github.io/react/docs/optimizing-performance.html#the-power-of-not-mutating-data) –

+0

Примеры с использованием обратного вызова prevState с добавлением различных методов. – pscl

+0

что делать, если я так делаю? 'this.setState ({ данные: [... this.state.data.slice (0, index), ... this.state.data.slice (index + 1)] });' Неправильно использовать 'this.state' вместо опции обратного вызова' prevState', показанной @ user1628461? –

1

Как уже упоминалось в ответе ephrion, фильтр() может быть медленным, особенно с большими массивами, поскольку он пытается найти индекс, который, по-видимому, уже определен. Это чистое, но неэффективное решение.

В качестве альтернативы можно просто «нарезать» желаемый элемент и объединить фрагменты.

var dummayArray = [];  
    this.setState({data:dummyArray.concat(this.state.data.slice(0,index),this.state.data.slice(index))}) 

Надеюсь, это поможет!

1

Вы можете использовать эту функцию, если вы хотите, чтобы удалить элемент (без индекса)

removeItem(item) { 
    this.setState(prevState => { 
    data: prevState.data.filter(i => i !== item) 
    }); 
} 
-1

Я использую это, надеюсь, что это не имеет никакого вопроса и помощь.

removeItem(item){ 
     const index = this.state.yourArray.indexOf(item); 
     if (index < 0) return 
     this.state.yourArray.splice(index, 1) 
     this.setState({yourArray: this.state.yourArray}) 
    } 
+0

Проблема с этим подходом заключается в том, что вы сами мутируете 'this.state'. Вы должны сделать копию 'this.state.yourArray' перед ее изменением. – aherriot

Смежные вопросы