reactjs 使用来自父组件的默认值ReactuseState

ogsagwnx  于 2023-03-17  发布在  React
关注(0)|答案(1)|浏览(140)

我在下面的React页面中调用了一个组件,该组件生成一个具有一些额外功能的文本字段,例如:将值复制到剪贴板或显示字符数。我遇到的问题是,当我试图从页面传递值时,它不起作用。

页面代码为:

import React, {useEffect, useRef, useState} from 'react'
import {useNavigate, useParams} from 'react-router-dom'

import {enterprise_info} from "../../config/AlertInfo";
import Header from '../../layouts/Header'

import EnterpriseMenu from "../../pages/enterprises/EnterpriseMenu";
import GetPermissionsMessage from "../../hooks/GetPermissionsMessage";

import Horizontal from "../../components/navigation/horizontal";
import Preloader from "../../components/card/Preloader";
import Alert from "../../components/alert/Alert";
import Text from "../../components/inputs/Text";
import Email from "../../components/inputs/Email";
import Button from "../../components/inputs/Button";

import UseGetFormData from "../../hooks/UseGetFormData";
import UseRequest from "../../hooks/UseRequest"

const EnterpriseInfo = () => {
    const {id} = useParams()
    const formRef = useRef()
    const history = useNavigate();
    const [errors, setErrors] = useState({})
    const [loading, setLoading] = useState(true)
    const [preloader, setPreloader] = useState({})
    const [enterprise, setEnterprise] = useState({})

    const fetchEnterprise = async () => {
        return await (await UseRequest(
            `/enterprises/get`,
            {request: {method: 'PUT', data: {limit: 1, offset: 0, _id: id}}}
        )).json();
    }

    useEffect(() => {
        const message = GetPermissionsMessage('enterprises', 'upsert')

        if(message){
            setPreloader({
                title: "You don't have permissions",
                description: message
            })
        }

        if (id != undefined) {
            fetchEnterprise().then((response) => {
                if(response?.entities?.length){
                    setEnterprise(response.entities[0])
                    setLoading(false)
                }
            });
        }

        setLoading(false)
    }, [])


    const handleSave = async (ev) => {
        ev.preventDefault()
        const formData = UseGetFormData(formRef)

        const response = await (await UseRequest(
            `/enterprises/upsert/${id ?? ''}`, {
                request: {
                    method: 'POST', data: {
                        name   : formData.get('name'),
                        email  : formData.get('email'),
                        phone  : formData.get('phone'),
                        website: formData.get('website'),
                        vat    : formData.get('vat'),
                    }
                }
            })).json();

        if (response.errors) {
            setErrors(response.errors)
        }

        if (!id && response._id) {
            history(`/enterprises/edit/${response._id}`)
        }
    }



    return (
        <div className="Enterprise">
            <Header title="Enterprise Manager" icon="enterprise"/>
            <div className="card">
                <Preloader loading={loading} title={preloader?.title} description={preloader.description} />
                {id && <Horizontal {...EnterpriseMenu} />}
                <form ref={formRef} className="max-width-500">
                    <Alert icon="info" type="primary" message={enterprise_info}/>
                    <Text required copy
                        name="name"
                        label="Name"
                        error={errors.name}
                        value={enterprise.name}
                        placeholder="Type company name"
                    />
                    <Email required
                        name="email"
                        label="Email"
                        error={errors.email}
                        value={enterprise.email}
                        placeholder="Type company email"
                    />
                    <Text required
                        name="phone"
                        label="Phone"
                        error={errors.phone}
                        value={enterprise.phone}
                        placeholder="Type company phone"
                    />
                    <Text
                        name="website"
                        label="Website"
                        error={errors.website}
                        value={enterprise.website}
                        placeholder="Type company website"
                    />
                    <Text
                        name="vat"
                        label="Vat number"
                        error={errors.vat}
                        value={enterprise.vat}
                        placeholder="Type vat number"
                    />
                    <Button type="primary" label="Save" icon="check"
                        onClick={handleSave}
                    />
                </form>
            </div>
        </div>
    )
}

export default EnterpriseInfo;

下面是文本组件的代码,其中inputValue没有更新。
我曾尝试直接使用由参数提供的{value}字段作为defaultValue,但这样做时,我无法读取值的长度,也无法在用户修改后将其复制到剪贴板。
我还尝试调用useEffect作为dependency [value],但它也不起作用。

import React, {useState} from "react";
import Icon from "../icon/Icon";
import UseCopyToClipboard from "../../hooks/UseCopyToClipboard";

const Text = (props) => {

    const {
        name, label, value, error, counter, copy, required,
        placeholder, className, onChange, onBlur, ...rest
    } = props

    const [inputValue, setInputValue] = useState(value)

    const handleChange = (ev) => {
        setInputValue(ev.target.content)
        if (typeof onChange == "function") {
            onChange(ev)
        }
    }

    const handleCopy = () => {
        UseCopyToClipboard(inputValue)
    }

    return (
        <React.Fragment>
            <div className="form-group">
                {label && <label className="Label">
                    {required && <span className="text-red required">* </span>}{label}
                    {error && <span className="error">{error}</span>}
                </label>}

                <div className="Input input-container">
                    <input
                        name={name}
                        type="text"
                        autoComplete="off"
                        value={inputValue}
                        onChange={handleChange}
                        placeholder={placeholder}
                        className={`form-control ${className ?? ''}`}
                        {...rest}
                    />

                    {counter && <span className="counter">{inputValue.length}</span>}
                    {copy && <span className="copy" onClick={handleCopy}><Icon name="copy"/></span>}
                </div>
            </div>
        </React.Fragment>
    )
}

export default Text;
qni6mghb

qni6mghb1#

问题可能在于您在enterprise加载之前显示组件,这意味着状态enterprise === {},结果是您传递给Text的值未定义,inputValue的初始状态也未定义。
对此有一些解决方案:
1.直到enterprise has a value才呈现窗体

// Set initial state to undefined
const [enterprise, setEnterprise] = useState(undefined)
{enterprise && <form ref={formRef} className="max-width-500">

1.删除子状态,并将enterprise用于所有内容,只需将一个on更改传递给所使用的Text组件即可

<Text required copy
    name="name"
    label="Name"
    error={errors.name}
    value={enterprise.name}
    onChange={(v)=> setEnterprise((curr)=> {...cur, name: v})}
    placeholder="Type company name"
/>

1.向窗体中添加一个键以在键更改时触发重新呈现

<form key={enterprise.name}>

最后一点:你的句柄改变功能也可能是一个因素。你使用setInputValue(ev.target.content)把它改变成setInputValue(ev.target.value)

相关问题