Javascript - Chức năng thuần túy và không tinh khiết


12

Tôi đã trải qua các định nghĩa của hai như:

Các hàm thuần túy là các hàm không cố gắng thay đổi đầu vào của chúng và luôn trả về cùng một kết quả cho cùng một đầu vào.

Thí dụ

function sum(a, b) {
  return a + b;
}

Và hàm Impure là một hàm thay đổi đầu vào của chính nó.

Thí dụ

function withdraw(account, amount) {
  account.total -= amount;
}

Các định nghĩa và đoạn mã được lấy từ các tài liệu chính thức của ReactJs .

Bây giờ, ai đó có thể cho tôi biết, làm thế nào tôi có thể mắc một số lỗi trong React / Redux , để sử dụng các hàm không tinh khiết khi cần các hàm thuần túy?


4
Chức năng không tinh khiết có tác dụng phụ. Một cái gì đó như window.getElementByIdvv để chạy cùng một chức năng với cùng một tham số có thể có kết quả khác nhau tùy thuộc vào các tác dụng phụ. Đó là nơi mà redux sẽ thất bại.
Dominik

Câu trả lời:


10

Phản ứng và Reduxcả hai đều cần các chức năng thuần túy kết hợp với tính bất biến để chạy theo kiểu có thể dự đoán được.

Nếu bạn không làm theo hai điều này, ứng dụng của bạn sẽ có lỗi, phổ biến nhất là React/Reduxkhông thể theo dõi các thay đổi và không thể kết xuất lại khi state/propthay đổi của bạn .

Về mặt React, hãy xem xét ví dụ sau:

let state = {
    add: 0,
}

function render() {
    //...
}
//pure function
function effects(state,action) {
//following immutability while updating state, not directly mutating the state.
    if(action == 'addTen') {
        return {...state, add: state.add + 10} 
    }
    return state;
}

function shouldUpdate(s) {
    if(s === state){
        return false
    }
    return true
}

state = effects(state, 'addTen')if(shouldUpdate(state)) {
    render();
}

Nhà nước được tổ chức bởi các đối tượng nhà nước chỉ có tài sản thêm. Ứng dụng này làm cho tài sản ứng dụng. Không nên luôn luôn hiển thị trạng thái khi có bất cứ điều gì xảy ra nhưng nên kiểm tra xem có thay đổi xảy ra trong đối tượng trạng thái hay không.

Giống như vậy, chúng ta có một hàm hiệu ứng, pure functionmà chúng ta sử dụng để ảnh hưởng đến trạng thái của chúng ta. Bạn thấy rằng nó trả về trạng thái mới khi trạng thái được thay đổi và trả về trạng thái tương tự khi không cần sửa đổi.

Chúng ta cũng có một shouldUpdatehàm kiểm tra bằng toán tử === xem trạng thái cũ và trạng thái mới có giống nhau không.

Để mắc lỗi về mặt React, bạn thực sự có thể làm như sau:

function effects(state,action) {

  doRandom(); // effects should only be called for updating state.
             // Doing any other stuff here would make effects impure.

    if(action == 'addTen') {
        return {...state, add: state.add + 10}
    }
    return state;
}

Bạn cũng có thể mắc lỗi bằng cách đặt trạng thái trực tiếp và không sử dụng effectschức năng.

function doMistake(newValue) {
    this.state = newValue
}

Ở trên không nên được thực hiện và chỉ effectsnên sử dụng chức năng để cập nhật trạng thái.

Về mặt React, chúng tôi gọi effectssetState.

Đối với Redux:

  1. combineReducersTiện ích của Redux kiểm tra các thay đổi tham chiếu.
  2. connectPhương thức của React-Redux tạo ra các thành phần kiểm tra các thay đổi tham chiếu cho cả trạng thái gốc và giá trị trả về từ các mapStatehàm để xem thành phần được bao bọc có thực sự cần phải kết xuất lại hay không.
  3. Gỡ lỗi du hành thời gian đòi hỏi bộ giảm tốc pure functionskhông có tác dụng phụ để bạn có thể nhảy chính xác giữa các trạng thái khác nhau.

Bạn có thể dễ dàng vi phạm ba điều trên bằng cách sử dụng các hàm không tinh khiết làm bộ giảm tốc.

Sau đây được lấy trực tiếp từ các tài liệu redux:

Nó được gọi là bộ giảm tốc vì đây là loại chức năng bạn sẽ chuyển qua Array.prototype.reduce(reducer, ?initialValue).
Điều rất quan trọng là bộ giảm tốc vẫn nguyên chất. Những điều bạn không bao giờ nên làm trong bộ giảm tốc:

Mutate its arguments;
Perform side effects like API calls and routing transitions;
Call non-pure functions, e.g. Date.now() or Math.random().

Đưa ra các đối số tương tự, nó sẽ tính toán trạng thái tiếp theo và trả về nó. Không ngạc nhiên. Không có tác dụng phụ. Không có lệnh gọi API. Không có đột biến. Chỉ là một phép tính.


7

Nói một cách đơn giản, nhà nước không thể bị đột biến. Một trường hợp mới của trạng thái nên được trả lại mỗi khi có thay đổi

Mã này không đúng:

const initialStates = {    
  items: ['item1']
}

export const ItemMaster = (state = initialStates, action) => {    
  switch (action.type) {
    case TYPES.ADD_ITEM:            
    {
        state.items.push(action.item)
        return state
    }
    default:
      return state
  }
}

Mã này khi được viết dưới dạng một hàm thuần túy bên dưới, Điều này trả về một thể hiện mới của mảng mà nó không sửa đổi chính mảng đó. Đây là lý do bạn nên sử dụng một thư viện như immer để xử lý sự bất biến

const initialStates = { 
  items: ['item1']
}

export const ItemMaster = (state = initialStates, action) => {    
  switch (action.type) {
    case TYPES.ADD_ITEM:            
    {

        state = {...state,items:state.items.concat(action.item)}
        return state
    }
    default:
      return state
  }
}

5

Bạn có thể làm cho các hàm thuần túy không tinh khiết bằng cách thêm các lệnh gọi API hoặc viết mã dẫn đến các hiệu ứng phụ.

Các hàm thuần túy phải luôn luôn đúng và tự giải thích, và không nên yêu cầu bạn tham khảo 3 hoặc 4 chức năng khác để hiểu những gì đang diễn ra.

// Pure Function
function USDtoEUR(USD, todayRate) {
  return USD * todayRate;
}

// Impure Function 
function USDtoEUR(USD) {
  const todayRate = getTodayRate();
  return USD * todayRate;
}

Trong trường hợp Phản ứng / Redux

const mapState = async state => {
  const { data } = await whatDoINeed()

  let mappedState = {}

  if (data.needDolphin) {
    mappedState.dolphin = state.dolphin
  }

  if (data.needShark) {
    mappedState.shark= state.shark
  }

  return mappedState;
}

// Or for Redux Reducer
// Bad
{
  setData: (state, payload) => {
   const set = whatToSet()
   return {
     ...state,
     set.dolphin ? ...{ dolphin: payload.dolphin } : ...{},
     set.shark ? ...{ shark : payload.shark } : ...{},
   }
  }
}

// Good
{
  setData: (state, payload) => {
   return {
     ...state,
     // Just send only the things need
     // to be sent
     ...payload
   }
  }
}

Điều này không nên được thực hiện . Mọi thứ mà chức năng kết nối hoặc chức năng giảm cần phải được cung cấp thông qua đối số hoặc được viết trong chức năng của nó. Nó không bao giờ nên nhận được từ bên ngoài.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.