Краткий ответ
Да!Оператор распространения ES6 может использоваться как замена для immutable.js целиком, но есть одно важное предостережение: вы всегда должны поддерживать ситуационную осведомленность.
ОЧЕНЬ Длинный ответ
Вы иваши коллеги-разработчики будут нести ответственность за поддержание неизменности на 100%, а не позволять им делать это за вас.Вот подробное описание того, как вы можете самостоятельно управлять неизменяемым состоянием, используя ES6 «оператор распространения», и его различные функции, такие как filter
и map
.
. Далее будет рассмотрено удаление и добавление значений вмассив или объект неизменным и мутированным способом.Я выхожу из системы initialState
и newState
в каждом примере, чтобы продемонстрировать, что мы мутировали initialState
.Это важно по той причине, что Redux не будет инструктировать пользовательский интерфейс для повторного рендеринга, если initialState
и newState
точно такие же.
Примечание: Immutable.js будетсбой приложения, если вы попробовали любое из приведенных ниже мутантных решений.
Удалите элемент из массива
Неизменяемым образом
const initialState = {
members: ['Pete', 'Paul', 'George', 'John']
}
const reducer = (state, action) => {
switch(action.type){
case 'REMOVE_MEMBER':
return {
...state,
members: state.members.filter(
member => member !== action.member
)
}
}
}
const newState = reducer(
initialState,
{type: 'REMOVE_MEMBER', member: 'Pete'}
);
console.log('initialState', initialState);
console.log('newState', newState);
Мутированный путь
const initialState = {
members: ['Pete', 'Paul', 'George', 'John']
}
const reducer = (state, action) => {
switch(action.type){
case 'REMOVE_MEMBER':
state.members.forEach((member, i) => {
if (member === action.member) {
state.members.splice(i, 1)
}
})
return {
...state,
members: state.members
}
}
}
const newState = reducer(
initialState,
{type: 'REMOVE_MEMBER', member: 'Pete'}
);
console.log('initialState', initialState);
console.log('newState', newState);
Добавить элемент в массив
Неизменяемый способ
const initialState = {
members: ['Paul', 'George', 'John']
}
const reducer = (state, action) => {
switch(action.type){
case 'ADD_MEMBER':
return {
...state,
members: [...state.members, action.member]
}
}
}
const newState = reducer(
initialState,
{type: 'ADD_MEMBER', member: 'Ringo'}
);
console.log('initialState', initialState);
console.log('newState', newState);
Мутированный путь
const initialState = {
members: ['Paul', 'George', 'John']
}
const reducer = (state, action) => {
switch(action.type){
case 'ADD_MEMBER':
state.members.push(action.member);
return {
...state,
members: state.members
}
}
}
const newState = reducer(
initialState,
{type: 'ADD_MEMBER', member: 'Ringo'}
);
console.log('initialState', initialState);
console.log('newState', newState);
Обновление массива
Неизменяемый способ
const initialState = {
members: ['Paul', 'Pete', 'George', 'John']
}
const reducer = (state, action) => {
switch(action.type){
case 'UPDATE_MEMBER':
return {
...state,
members: state.members.map(member => member === action.member ? action.replacement : member)
}
}
}
const newState = reducer(
initialState,
{type: 'UPDATE_MEMBER', member: 'Pete', replacement: 'Ringo'}
);
console.log('initialState', initialState);
console.log('newState', newState);
Мутированный путь
const initialState = {
members: ['Paul', 'Pete', 'George', 'John']
}
const reducer = (state, action) => {
switch(action.type){
case 'UPDATE_MEMBER':
state.members.forEach((member, i) => {
if (member === action.member) {
state.members[i] = action.replacement;
}
})
return {
...state,
members: state.members
}
}
}
const newState = reducer(
initialState,
{type: 'UPDATE_MEMBER', member: 'Pete', replacement: 'Ringo'}
);
console.log('initialState', initialState);
console.log('newState', newState);
Объединение массивов
Неизменяемый способ
const initialState = {
members: ['Paul', 'Ringo']
}
const reducer = (state, action) => {
switch(action.type){
case 'MERGE_MEMBERS':
return {
...state,
members: [...state.members, ...action.members]
}
}
}
const newState = reducer(
initialState,
{type: 'MERGE_MEMBERS', members: ['George', 'John']}
);
console.log('initialState', initialState);
console.log('newState', newState);
Мутировал
const initialState = {
members: ['Paul', 'Ringo']
}
const reducer = (state, action) => {
switch(action.type){
case 'MERGE_MEMBERS':
action.members.forEach(member => state.members.push(member))
return {
...state,
members: state.members
}
}
}
const newState = reducer(
initialState,
{type: 'MERGE_MEMBERS', members: ['George', 'John']}
);
console.log('initialState', initialState);
console.log('newState', newState);
Приведенные выше примеры мутирования массива могут показаться очевидным плохим опытом для опытного разработчика, но простой ловушкой для кого-то нового на сцене.Мы надеемся, что любой из фрагментов кода Mutated way окажется в обзоре кода, но это не всегда так.Давайте немного поговорим об объектах, которые более громоздки при самостоятельной обработке неизменности.
Удалить из объекта
Неизменяемый способ
const initialState = {
members: {
paul: {
name: 'Paul',
instrument: 'Guitar'
},
stuart: {
name: 'Stuart',
instrument: 'Bass'
}
}
}
const reducer = (state, action) => {
switch(action.type){
case 'REMOVE_MEMBER':
let { [action.member]: _, ...members } = state.members
return {
...state,
members
}
}
}
const newState = reducer(
initialState,
{type: 'REMOVE_MEMBER', member: 'stuart'}
);
console.log('initialState', initialState);
console.log('newState', newState);
Мутировал
const initialState = {
members: {
paul: {
name: 'Paul',
instrument: 'Guitar'
},
stuart: {
name: 'Stuart',
instrument: 'Bass'
}
}
}
const reducer = (state, action) => {
switch(action.type){
case 'REMOVE_MEMBER':
delete state.members[action.member]
return {
...state,
members: state.members
}
}
}
const newState = reducer(
initialState,
{type: 'REMOVE_MEMBER', member: 'stuart'}
);
console.log('initialState', initialState);
console.log('newState', newState);
Обновление объекта
Неизменяемый способ
const initialState = {
members: {
paul: {
name: 'Paul',
instrument: 'Guitar'
},
ringo: {
name: 'George',
instrument: 'Guitar'
}
}
}
const reducer = (state, action) => {
switch(action.type){
case 'CHANGE_INSTRUMENT':
return {
...state,
members: {
...state.members,
[action.key]: {
...state.members[action.member],
instrument: action.instrument
}
}
}
}
}
const newState = reducer(
initialState,
{type: 'CHANGE_INSTRUMENT', member: 'paul', instrument: 'Bass'}
);
console.log('initialState', initialState);
console.log('newState', newState);
Мутировал
const initialState = {
members: {
paul: {
name: 'Paul',
instrument: 'Guitar'
},
ringo: {
name: 'George',
instrument: 'Guitar'
}
}
}
const reducer = (state, action) => {
switch(action.type){
case 'CHANGE_INSTRUMENT':
state.members[action.member].instrument = action.instrument
return {
...state,
members: state.members
}
}
}
const newState = reducer(
initialState,
{type: 'CHANGE_INSTRUMENT', member: 'paul', instrument: 'Bass'}
);
console.log('initialState', initialState);
console.log('newState', newState);
Если вы сделали это так далеко, поздравляем!Я знаю, что этот пост был длинным, но я чувствовал, что важно продемонстрировать все мутированные способы , которые вам понадобятся, чтобы предотвратить себя без Immutable.js.Одним из огромных преимуществ использования Immutable.js, помимо того, что мешает писать плохой код, являются вспомогательные методы, такие как mergeDeep
и updateIn
Immutable.JS
mergeDeep
const initialState = Immutable.fromJS({
members: {
paul: {
name: 'Paul',
instrument: 'Guitar'
},
ringo: {
name: 'George',
instrument: 'Guitar'
}
}
})
const reducer = (state, action) => {
switch (action.type) {
case 'ADD_MEMBERS':
return state.mergeDeep({members: action.members})
}
}
const newState = reducer(
initialState,
{
type: 'ADD_MEMBERS',
members: {
george: { name: 'George', instrument: 'Guitar' },
john: { name: 'John', instrument: 'Guitar' }
}
}
);
console.log('initialState', initialState);
console.log('newState', newState);
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.min.js"></script>
updateIn
const initialState = Immutable.fromJS({
members: {
paul: {
name: 'Paul',
instrument: 'Guitar'
},
ringo: {
name: 'George',
instrument: 'Guitar'
}
}
})
const reducer = (state, action) => {
switch (action.type) {
case 'CHANGE_INSTRUMENT':
return state.updateIn(['members', action.member, 'instrument'], instrument => action.instrument)
}
}
const newState = reducer(
initialState,
{type: 'CHANGE_INSTRUMENT', member: 'paul', instrument: 'Bass'}
);
console.log('initialState', initialState);
console.log('newState', newState);
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.min.js"></script>