不受控制的输入反应

Posted

技术标签:

【中文标题】不受控制的输入反应【英文标题】:Uncontrolled input React 【发布时间】:2020-10-09 21:40:20 【问题描述】:

我有以下代码:

import React,  Component  from 'react'
import axios from 'axios'
import Navbar from '../Navbar'
import  Avatar, TextField, Button, Container, CircularProgress  from '@material-ui/core'
import Alert from '@material-ui/lab/Alert'

class PrivateProfile extends Component 
    constructor(props) 
        super(props);
        this.state =  
            user: null,
            id: null,
            image: null,
            pp: null,
            username: 'AnonymousUser',
            showSuccess: false
        
        this.handleChange = this.handleChange.bind(this)
        this.handleSubmit = this.handleSubmit.bind(this)
        this.handleFileChange = this.handleFileChange.bind(this)
    
    componentDidMount() 
        axios.get('http://127.0.0.1:8000/users/profile')
        .then(res => 
            this.setState( 
                user: res.data,
                id: res.data.id,
                username: res.data.username,
                pp: res.data.pp 
            )
        )
        .catch(err => console.log(err))
    
    handleSubmit(e) 
        e.preventDefault()
        const fd = new FormData()
        fd.append('pp', this.state.image)
        fd.append('username', this.state.user.username)
        fd.append('email', this.state.user.email)
        fd.append('bio', this.state.user.bio)
        const d = 
            pp : this.state.image,
            username : this.state.user.username,
            email : this.state.user.email,
            bio : this.state.user.bio
        
        console.log('d', d)
        console.log('fd', fd)
        axios.put(`http://127.0.0.1:8000/users/profile/update/$this.state.id/`, fd, 
            headers: 
                'Content-Type': 'multipart/form-data'
            
        )
        .then(res => 
            this.setState(
                user: res.data,
                id: res.data.id,
                pp: res.data.pp,
                image: null,
                username: res.data.username,
                showSuccess: true
            )
        )
        .catch(err => console.log(err))
    
    handleChange(e) 
        this.setState(
            user: 
                [e.target.name]: e.target.value
            
        )
    
    handleFileChange(e) 
        this.setState(image: e.target.files[0])
    
    render()  
        let message
        let alert
        if (this.state.user !== null) 
            if (!this.state.user.bio) 
                message = <h4>Please update your profile below.</h4>
            
            if (this.state.showSuccess) 
                alert = <Alert action=<Button onClick=() => this.setState(showSuccess: false)>Close</Button> severity='success'>Profile Successfully Updated</Alert>
            
            return ( 
                <div>
                    <Navbar />
                    <Container style=background: '#f7f4e9'>
                        <div style=height: '60px'></div>
                        <h2>Your Profile</h2>
                        <Avatar src=this.state.user.pp alt=this.state.user.username />
                        message
                        alert
                        <h4>Your data:</h4>
                        <form onSubmit=this.handleSubmit>
                            <p>Profile Pic</p>
                            <input type="file" onChange=this.handleFileChange/>
                            <br></br>
                            <br></br>
                            <TextField label='Username' name="username" onChange=this.handleChange type="text" value=this.state.user.username />
                            <br></br>
                            <br></br>
                            <TextField label='Email' name="email" onChange=this.handleChange type="email" value=this.state.user.email />
                            <br></br>
                            <br></br>
                            <TextField label='Bio' name="bio" onChange=this.handleChange type="text" value=this.state.user.bio />
                            <br></br>
                            <br></br>
                            <br></br>
                            <Button type="submit" value="submit">Update</Button>
                        </form>
                    </Container>
                </div>
            )
         else 
            return <CircularProgress />
        
    


export default PrivateProfile

我收到错误消息:警告:组件正在将文本类型的受控输入更改为不受控制。输入元素不应从受控切换到不受控(反之亦然)。决定在组件的生命周期内使用受控输入元素还是不受控输入元素。

谁能帮我修一下。

【问题讨论】:

您能否确保用户名、电子邮件和个人简历不为空值。例如 value=this.state.user.username || '' 这能回答你的问题吗? React - changing an uncontrolled input 当我做 value=this.state.whatever || '',每当其中一个字段发生变化时,其他字段也会变成空字符串 如我所见,您必须在 handleChange 中合并旧状态。 this.setState( user: ...this.state.user, [e.target.name]: e.target.value ) 乍一看这似乎是正确的。您是否尝试过调试您的 handleChange 方法?它是否根据输入的名称访问正确的键? 【参考方案1】:

由于您使用 null 初始化状态值并像 value=this.state.user.username 一样使用它,并更新状态,您会收到这样的错误:

警告:组件正在将文本类型的受控输入更改为不受控制。

要控制它的状态,像这样使用它:

value=this.state.user.username || ''

根据我的评论,您在这里有问题:

handleChange(e) 
  this.setState(
    user: 
     [e.target.name]: e.target.value
    
  )

用户状态总是会随着你的任何输入变化而改变,你需要像这样:

handleChange(e) 
  this.setState(
    user: 
     ...this.state.user,
     [e.target.name]: e.target.value
    
  )

【讨论】:

当我做 value=this.state.whatever || '',每当其中一个字段发生变化时,其他字段也会变成空字符串 那么,这不是那个问题。您可以查看 onChange 处理程序。 这个答案应该是正确的。我喜欢切换到useState 钩子的众多原因之一 - 更新嵌套状态时不再需要以旧状态传播。假设您正在构建一个平面数据结构。 最好用'' 而不是null 来初始化表单值。然后你不需要在任何地方都做value || '',并且可以相信它们在代码的其他部分也是不可为空的。 @ATOMP 是的。但在某些情况下,我们可能需要有 null 值,例如。初始状态用于获取某些结果?

以上是关于不受控制的输入反应的主要内容,如果未能解决你的问题,请参考以下文章

警告:组件正在将文本类型的受控输入更改为不受控制。 (反应.js)

在表单控制输入中反应 js useReducer 钩子

markdown 反应受控和不受控制的组件

反应控制的输入光标跳跃

改变反应表达,保持观察者

在更改方法上使用输入子级反应控制父级状态