根据公式动态计算平方英尺

问题描述 投票:0回答:1

我正在使用React / Formik / Yup和Node / Express API + Postgres数据库构建应用程序。该应用程序的一项功能需要根据包装的样式和相关公式计算盒子/其他纸板包装的平方英尺。一个示例是公式为((length * 2 + width * 2 + x1) * (height * 2)) / 144的“ RSC”样式框。这两个都作为字符串存储在数据库中的对象中。

我当前的解决方案起作用,但是如果用户遗漏了必填字段,则应用程序将崩溃。我遇到的问题是必填字段在设计之间有所不同。

import React, { useState, useEffect } from 'react';

// importing axios for http requests
import axios from 'axios'; 

// Formik/yup (form validation library) import
import { withFormik, Form, Field } from 'formik'
import * as yup from 'yup'; 

// styling imports 
import './BoxCalculator.scss'; 

const BoxCalculator = ({ values,  touched, errors }) => {

    //useState hook to store options we dynamically render in the <select> tag
    const [ boxStyles, setBoxStyles ] = useState(); 

    // pulling the list of possible box formulas from the API on page render, going to save it to an array
    useEffect(() => {
        axios.get('http://localhost:5000/api/box-styles')
        .then(res => {
            setBoxStyles(res.data.data); 
            console.log(boxStyles); 
        })
        .catch(err => {
            console.log(err); 
        }); 
    // this next line eliminates the linter error causes by having an empty dependency array
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [])

    const calculateFootage = () => {
        // selecting the Box Style the user has selected
        const style = document.getElementById('style').value; 

        // filtering the array to find the box_style_formula based on the 
        let styleFormulaArr = boxStyles.filter(box => box.box_style_name === style)
        let formula = styleFormulaArr[0].box_style_formula;

        formula = formula.replace(/length/gi, values.length)
        formula = formula.replace(/width/gi, values.width)
        formula = formula.replace(/height/gi, values.height) 
        formula = formula.replace(/x1/gi, values.x1) 
        formula = formula.replace(/x2/gi, values.x2) 
        formula = formula.replace(/x3/gi, values.x3)   
        formula = formula.replace(/x4/gi, values.x4) 
        formula = formula.replace(/x5/gi, values.x5) 
        formula = formula.replace(/x6/gi, values.x6) 
        formula = formula.replace(/x7/gi, values.x7) 
        formula = formula.replace(/x8/gi, values.x8) 
        formula = formula.replace(/x9/gi, values.x9) 
        formula = formula.replace(/x10/gi, values.x10)

        // disabling the "eval may be harmful" error READ TO UNDERSTAND WHY: https://eslint.org/docs/rules/no-eval
        // eslint-disable-next-line
        const decimal = eval(formula); 


        document.getElementById('sqft').value = `${decimal.toFixed(4)} sq. ft` 
        console.log(document.getElementById('sqft').value)

    }


    if(boxStyles) {
        return ( 
            <>
                <Form className="boxcalc-wrapper">
                    <label>Box Style:<br/>
                        {touched.style && errors.style && <p>{errors.style}</p>}
                        <select type="number"
                        name="style"
                        multiple={false}
                        id="style"
                        className="boxcalc-field"
                        >
                            {boxStyles.map((opt) => {
                                return (<option key={opt.id}>{opt.box_style_name}</option>)
                            })}
                        </select>
                    </label>
                    <label>Length:<br/>
                        {touched.length && errors.length && <p>{errors.length}</p>}
                        <Field type="number"
                        name="length"
                        className="boxcalc-field"
                        />
                    </label>
                    <label>Width:<br/>
                        {touched.width && errors.width && <p>{errors.width}</p>}
                        <Field type="number"
                        name="width"
                        className="boxcalc-field"
                        />
                    </label>
                    <label>Height:<br/>
                        {touched.height && errors.height && <p>{errors.height}</p>}
                        <Field type="number"
                        name="height"
                        className="boxcalc-field"
                        />
                    </label>
                    <label>X1:<br/>
                        {touched.x1 && errors.x1 && <p>{errors.x1}</p>}
                        <Field type="number"
                        name="x1"
                        className="boxcalc-field"
                        />
                    </label>
                    <label>X2:<br/>
                        {/* {touched.x2 && errors.x2 && <p>{errors.x2}</p>} */}
                        <Field type="number"
                        name="x2"
                        className="boxcalc-field"
                        />
                    </label>
                    <label>X3:<br/>
                        <Field type="number"
                        name="x3"
                        className="boxcalc-field"
                        />
                    </label>
                    <label>X4:<br/>
                        <Field type="number"
                        name="x4"
                        className="boxcalc-field"
                        />
                    </label>
                    <label>X5:<br/>
                        <Field type="number"
                        name="x5"
                        className="boxcalc-field"
                        />
                    </label>
                    <label>X6:<br/>
                        <Field type="number"
                        name="x6"
                        className="boxcalc-field"
                        />
                    </label>
                    <label>X7:<br/>
                        <Field type="number"
                        name="x7"
                        className="boxcalc-field"
                        />
                    </label>
                    <label>X8:<br/>
                        <Field type="number"
                        name="x8"
                        className="boxcalc-field"
                        />
                    </label>
                    <label>X9:<br/>
                        <Field type="number"
                        name="x9"
                        className="boxcalc-field"
                        />
                    </label>
                    <label>X10:<br/>
                        <Field type="number"
                        name="x10"
                        className="boxcalc-field"
                        />
                    </label> */}
                    <label>Name Box:<br/>
                        <Field type="number"
                        name="name"
                        className="boxcalc-field"
                        />
                    </label>
                    <button className="calculate-box" onClick={calculateFootage}>Calculate</button>
                    <label>Square Footage:<br/>
                        <Field 
                        type="text"
                        name="footage"
                        className="boxcalc-field"
                        id="sqft"
                        readOnly={true}
                        />
                    </label>
                    <p className="save-question">Need to save this box?</p>
                    <div className="save-btn-wrapper">
                        <p className="no-thanks">No thanks</p>
                        <button className="save-btn">Save</button>
                    </div>
                </Form>
            </>
         );
    } else {
        return <p></p> 
    } 
}

const FormikBoxCalculator = withFormik({
    mapPropsToValues({ style, length, width, height, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, name, sqft, boxStyles }) {
        return {
            style: style || '',
            length: length || '',
            width: width || '',
            height: height || '',
            x1: x1 || '',
            x2: x2 || '', 
            x3: x3 || '', 
            x4: x4 || '', 
            x5: x5 || '', 
            x6: x6 || '', 
            x7: x7 || '', 
            x8: x8 || '', 
            x9: x9 || '', 
            x10: x10 || '',  
            name: name || '',
            sqft: sqft || '',
            boxStyles: boxStyles || ''
        }
    }, 

     ============= YUP VALIDATION SCHEMA ===============
     validationSchema: function createSchema() {
         return yup.object().shape({
             style: yup.string().required("Style is required"),
             length: yup.number().required("Length is required"),
             width: yup.number().required("Width is required"),
             height: yup.number().required("Height is required"),
         })}, 

     ============== END SCHEMA ==============

})(BoxCalculator); 



export default FormikBoxCalculator;

有人知道一种仅要求当前设计使用的字段的干净方法吗?例如((length * 2 + width * 2 + x1) * (height * 2)) / 144将具有必填字段的长度,宽度,高度和x1。

我还希望在calculateFootage函数中使用“ eval”时提供一些输入。我已经在文档上阅读了它(在其用法上方的注释中链接),因此在这里,几乎总是有一个更好的解决方案,但是eval是我唯一可以使用的方法。

reactjs eval formik yup
1个回答
0
投票

您可以在函数中循环一组属性,并且仅当替换在函数中并且因此是该函数的必填字段时才进行替换?

这可能看起来像,

const attrs = ['length', 'width', 'height', 'x1', 'x2', 'x3', 'x4', .... etc]
for (i in attrs) {
  const attr = attrs[i];
  if (attr in formula) {
    formula = formula.replace(attr, values[attr])
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.