React类组件方法:我的代码是命令式的吗?

时间:2018-05-26 17:05:31

标签: javascript reactjs

我是新的反应,也是功能,命令,声明的条款。而且我知道纯函数很容易测试。我自学成才用Javascript编程。到目前为止,它正在工作,但我的目标是学习编写干净和可维护的代码。 我的问题是下面的addProductToSaleList方法是坏的和不可测试的,因为它是必要的?我怎么能以不同的方式做到这一点。

class SaleComponent extends React.Component {

    addProductToSaleList = (values, dispatch, props) => {
        //filter product from productList 
        const productFound = props.productList.filter(product => {
            if (values.productCode === product.code.toString()) {
                return product
            }
            return undefined
        })[0]

        if (productFound) {

            // filter sale list to check if there is already product in the list.
            const detailFound = props.saleItem.details.filter(detail => {
                if (productFound.name === detail.product) {
                    return detail
                }
                return undefined
            })[0]

            // if it is exist just increment the qty
            if (detailFound) { 
                const { sub_total, ...rest } = detailFound
                props.dispatcher('UPDATE_SALEDETAIL_ASYNC', {
                    ...rest,
                    qty: parseInt(detailFound.qty, 10) + 1
                })

            // if it is not exist add new one
            } else { 
                props.dispatcher('ADD_SALEDETAIL_ASYNC', {
                    product: productFound.id,
                    price: productFound.price,
                    qty: 1
                })
            }
        } else {

            alert('The product code you add is not exist in product list');
        }
    }
    render() {
        // Render saleList
    }
}

1 个答案:

答案 0 :(得分:2)

我相信这个问题应该转到Code Review,但我会试一试。部分代码可以改进

const productFound = props.productList.filter(product => {
        if (values.productCode === product.code.toString()) {
            return product
        }
        return undefined
    })[0]

首先,filter函数接收回调,并且每个项目都将执行回调。如果回调返回一个解释为true的值,它将返回函数将构建的新数组中的项。否则,它将跳过该项目。假设您正在尝试在代码中找到一个项目,您可以使用函数find直接返回该元素(不需要[0]),或者如果该项不是找到。所以你的代码可以重写为

const productFound = props.productList.find(product => values.productCode === product.code.toString());

注意:没有IE支持。

然后,如果找不到该值,您只需提醒并执行early return。 (您可能还希望以不同的方式处理错误,格式比普通警报更好。)

代码看起来像

if (!productFound) {
    alert('The product code you add is not exist in product list');
    return;
}
// rest of the function

为了查找详细信息,您还可以使用find方法

const detailFound = props.saleItem.details.find(detail => productFound.name === detail.product);

然后只需调用代码的其余部分

// if it is exist just increment the qty
    if (detailFound) { 
        const { sub_total, ...rest } = detailFound
        props.dispatcher('UPDATE_SALEDETAIL_ASYNC', {
            ...rest,
            qty: parseInt(detailFound.qty, 10) + 1
        })

    // if it is not exist add new one
    } else { 
        props.dispatcher('ADD_SALEDETAIL_ASYNC', {
            product: productFound.id,
            price: productFound.price,
            qty: 1
        })
    }

另一项改进:

您正在接收调度功能作为参数,但您并未使用它。所以你可以从函数声明中删除它

(values, props) => { ... } 

你可以把最后一部分分成两个不同的功能,比如

const getAction = details => `${detailFound ? 'UPDATE' : 'ADD'}_SALEDETAIL_ASYNC`;

const getObject = (details, productFound) => {
        if (!details) {
            return {
                product: productFound.id,
                price: productFound.price,
                qty: 1
            };
        }
        const { sub_total, ...rest } = detailFound;
        return  {
            ...rest,
            qty: parseInt(detailFound.qty, 10) + 1
        };
    }

然后只需致电

props.dispatcher(getAction(details), getObject(details, productFound));

最终结果看起来像

addProductToSaleList = (values, props) => {
    //filter product from productList 
    const productFound = props.productList.find(product => values.productCode === product.code.toString());

    if (!productFound) {
        alert('The product code you add is not exist in product list');
        return;
    }

    // filter sale list to check if there is already product in the list.
    const detailFound = props.saleItem.details.find(detail => productFound.name === detail.product);

    const getAction = details => `${details ? 'UPDATE' : 'ADD'}_SALEDETAIL_ASYNC`;

    const getObject = (details, productFound) => {
        if (!details) {
            return {
                product: productFound.id,
                price: productFound.price,
                qty: 1
            };
        }
        const { sub_total, ...rest } = details;
        return  {
            ...rest,
            qty: parseInt(details.qty, 10) + 1
        };
    }

    props.dispatcher(getAction(details), getObject(details, productFound));
}
  

我的问题是下面的方法addProductToSaleList是坏的   不可测试,因为这是必要的

你的代码是可测试的,没有外部依赖。所以你可以传递模拟的值和道具,并添加单元测试。这意味着,传递假的valuesprops(它们只是普通的js对象)并对其进行断言。

例如:

您可以模拟dispatcher函数并在productList和saleItem.details中给出假值,您可以看到是否使用正确的值调用dispatcher。你应该测试那个

的不同组合

Mock alert函数(同样,我会使用另一种UI方法)并验证它是否被调用,并且没有其他代码被调用(断言你的假dispatcher未被调用)。像这样:

   let actionToAssert;
    let objectToAssert;
    let values = { productCode: 'somecode' };
    let props = { 
      productList: // your item listm with id and price, name, etc,
      saleItem: {
         details: // your details array here
      }
      dispatcher: (action, newObject) => {
         actionToAssert = action;
         objectToAssert = newObject;
      }   
    }
    addProductToSaleList(values, props);    // make here assertions over actionToAssert and objectToAssert