状态改变后,对输入的关注会丢失

发布于 2025-01-11 11:26:41 字数 6168 浏览 0 评论 0原文

每次重新渲染和更新状态时,我的输入框都会失去焦点。我想知道如何将焦点保留在文本框上,直到用户点击离开。

我的应用程序输入每个产品的材料成本并计算该产品的总成本。我希望在输入更新后重新渲染组件以显示更新的总数。似乎每次材料成本发生变化时都会计算总计并且状态都会更新,但用户每次都必须手动重新选择输入框,因为焦点消失了。

这是我的应用程序的屏幕截图(为简单起见,删除了表中元素的一些代码)

在此处输入图像描述我不确定这对解决问题是否必要,但这就是数据的样子。在此示例中,我保存数组的第一个元素。

export let data = 
    {
        name: "Name",
        description:
            "",
        products: [
            {
                id: 1,
                name: "Name 1",
                material: 1.05,
                time: 25,
                total: 0,
            },
            {
                id: 2,
                name: "Name 2",
                material: 3,
                time: 252,
                total: 0,
            },
        ],
    }

这是父组件。它具有主渲染以及 setTotal 和 setMaterial 函数。渲染映射通过每个productData.products,以便子组件可以渲染它们。

setTotal 和 setMaterial 函数几乎相同(我确信有一种方法可以重构它)。用户在元素中键入数字后都会调用这两个函数。


function CompareCard({ type, labor }) {

    const [productData, setProductData] = useState(data);

    const setTotal = (id, total) => {
        const productPrevious = productData.products.find(function (rec) {
            return rec.id === id;
        });

        const productUpdated = {
            ...productPrevious,
            total: total,
        };

        const productNew = productData.products.map(function (rec) {
            return rec.id === id ? productUpdated : rec;
        });

        const productFullNew = {
            ...productData,
            products: productNew,
        };0

        //calculate new final totals
        let newFinalTotal = 0;
        let newFinalMaterial = 0;
        let newFinalTime = 0;
        productFullNew.products.map((product) => {
            newFinalTotal += product.total;
            newFinalMaterial += product.material;
            newFinalTime += product.time;
        });

        productFullNew.finalTotal.total = newFinalTotal;
        productFullNew.finalTotal.material = newFinalMaterial;
        productFullNew.finalTotal.time = newFinalTime;

        setProductData(productFullNew);
    };

    const setMaterial = (id, materialCost) => {
        const productPrevious = productData.products.find(function (rec) {
            return rec.id === id;
        });

        const productUpdated = {
            ...productPrevious,
            material: materialCost,
        };

        const productNew = productData.products.map(function (rec) {
            return rec.id === id ? productUpdated : rec;
        });

        const productFullNew = {
            ...productData,
            products: productNew,
        };

        setProductData(productFullNew);
    };
    return (
        <div className="Card">
            <h3> {productData.name} </h3>
            <p>{productData.description}</p>
            <table className="table">
                <thead>
                    <tr>
                        
                        <th scope="col">
                            <p>
                                <b> Material </b>
                            </p>
                        </th>
                        
                        <th scope="col">
                            <p>
                                <b> Labor </b>
                            </p>
                        </th>
                        <th scope="col">
                            <p>
                                <b> Total</b>
                            </p>
                        </th>
                    </tr>
                </thead>
                <tbody id={`${productData.name}`}>
                    {productData.products.map((product) => {
                        return (
                            <Products
                                key={product.id}
                                product={product}
                                labor={3}
                                setMaterial={setMaterial}
                                setTotal={setTotal}
                            />
                        );
                    })}
                </tbody>
            </table>
        </div>
    );
}

export default CompareCard;

这是子元素。它单独处理每个产品。

该元素居住在这里。

import React, { useState, useEffect } from "react";
function Products({ product, labor, setMaterial, setTotal }) {
    function setMaterialState(newMaterial) {
        product.material = newMaterial;
    }

    function calcTotal() {
        product.total = labor + product.material;
    }
    

    if (product.total === 0) {
        calcTotal();
    }

    useEffect(() => {
        setTotal(product.id, product.total);
    }, [product.total]);

    useEffect(() => {
        setMaterial(product.id, product.material);

        //setTotal(product.id, product.material + labor);
    }, [product.material]);

    function ProductMaterial() {
        const [name, setName] = useState("");

        function handleChange(e) {
            setName(parseFloat(e.target.value));
            setMaterialState(parseFloat(e.target.value));
            setMaterial(product.id, product.material);
            calcTotal();
            setTotal(product.id, product.total);
        }

        return (
            <input
                type="number"
                name="firstName"
                onChange={handleChange}
                value={product.material}
            />
        );
    }

    return (
        <tr key={product.name}>
            
            <td>
                <ProductMaterial product={product} />{" "}
    
            <td id={`total-${product.id}`}>{product.total}</td>
        </tr>
    );
}

export default Products;

My input box is losing focus everytime I rerender and update state. I'm wondering how to retain the focus on the textbox until the user clicks away.

My application takes an input for material cost of each product and calculates the total of that product. I would like the component to be rerendered to show the updated total after the input is updated. It seems that the total is calculated and the state is updating every time the material cost is changed, but the user has to manually reselect the input box for every time because the focus is gone.

Here's a screenshot of my application (some code for elements in the table were removed for simplicity)

enter image description here
I'm not sure this is necessary for the problem, but this is what the data looks like. In this example I am saving the first element of the array.

export let data = 
    {
        name: "Name",
        description:
            "",
        products: [
            {
                id: 1,
                name: "Name 1",
                material: 1.05,
                time: 25,
                total: 0,
            },
            {
                id: 2,
                name: "Name 2",
                material: 3,
                time: 252,
                total: 0,
            },
        ],
    }

This is the parent component. It has the main render and the setTotal and setMaterial functions. The render maps through each of the productData.products so the child component can render them.

The setTotal and setMaterial functions are almost identical (I'm sure there's a way to refactor that). The functions are both called after the user types a number within the element.


function CompareCard({ type, labor }) {

    const [productData, setProductData] = useState(data);

    const setTotal = (id, total) => {
        const productPrevious = productData.products.find(function (rec) {
            return rec.id === id;
        });

        const productUpdated = {
            ...productPrevious,
            total: total,
        };

        const productNew = productData.products.map(function (rec) {
            return rec.id === id ? productUpdated : rec;
        });

        const productFullNew = {
            ...productData,
            products: productNew,
        };0

        //calculate new final totals
        let newFinalTotal = 0;
        let newFinalMaterial = 0;
        let newFinalTime = 0;
        productFullNew.products.map((product) => {
            newFinalTotal += product.total;
            newFinalMaterial += product.material;
            newFinalTime += product.time;
        });

        productFullNew.finalTotal.total = newFinalTotal;
        productFullNew.finalTotal.material = newFinalMaterial;
        productFullNew.finalTotal.time = newFinalTime;

        setProductData(productFullNew);
    };

    const setMaterial = (id, materialCost) => {
        const productPrevious = productData.products.find(function (rec) {
            return rec.id === id;
        });

        const productUpdated = {
            ...productPrevious,
            material: materialCost,
        };

        const productNew = productData.products.map(function (rec) {
            return rec.id === id ? productUpdated : rec;
        });

        const productFullNew = {
            ...productData,
            products: productNew,
        };

        setProductData(productFullNew);
    };
    return (
        <div className="Card">
            <h3> {productData.name} </h3>
            <p>{productData.description}</p>
            <table className="table">
                <thead>
                    <tr>
                        
                        <th scope="col">
                            <p>
                                <b> Material </b>
                            </p>
                        </th>
                        
                        <th scope="col">
                            <p>
                                <b> Labor </b>
                            </p>
                        </th>
                        <th scope="col">
                            <p>
                                <b> Total</b>
                            </p>
                        </th>
                    </tr>
                </thead>
                <tbody id={`${productData.name}`}>
                    {productData.products.map((product) => {
                        return (
                            <Products
                                key={product.id}
                                product={product}
                                labor={3}
                                setMaterial={setMaterial}
                                setTotal={setTotal}
                            />
                        );
                    })}
                </tbody>
            </table>
        </div>
    );
}

export default CompareCard;

This is the child element. It handles each product individually.

The element lives here.

import React, { useState, useEffect } from "react";
function Products({ product, labor, setMaterial, setTotal }) {
    function setMaterialState(newMaterial) {
        product.material = newMaterial;
    }

    function calcTotal() {
        product.total = labor + product.material;
    }
    

    if (product.total === 0) {
        calcTotal();
    }

    useEffect(() => {
        setTotal(product.id, product.total);
    }, [product.total]);

    useEffect(() => {
        setMaterial(product.id, product.material);

        //setTotal(product.id, product.material + labor);
    }, [product.material]);

    function ProductMaterial() {
        const [name, setName] = useState("");

        function handleChange(e) {
            setName(parseFloat(e.target.value));
            setMaterialState(parseFloat(e.target.value));
            setMaterial(product.id, product.material);
            calcTotal();
            setTotal(product.id, product.total);
        }

        return (
            <input
                type="number"
                name="firstName"
                onChange={handleChange}
                value={product.material}
            />
        );
    }

    return (
        <tr key={product.name}>
            
            <td>
                <ProductMaterial product={product} />{" "}
    
            <td id={`total-${product.id}`}>{product.total}</td>
        </tr>
    );
}

export default Products;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

何必那么矫情 2025-01-18 11:26:41

我发现 Sergi Juanati 回答了一个类似的 stackoverflow 问题,对我有用 在 React ES6 中,为什么输入字段在输入字符后会失去焦点?

我将保存输入 return 语句的函数切换为以下语法:

const Products = ({ product, labor, setMaterial, setTotal }) => {};

以及对函数:

{ProductMaterial({product:product})}

I found a similar stackoverflow question answered by Sergi Juanati that worked for me In React ES6, why does the input field lose focus after typing a character?

I switched my function that holds the input return statement to this syntax:

const Products = ({ product, labor, setMaterial, setTotal }) => {};

and the call to the function to this:

{ProductMaterial({ product: product })}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文