简体   繁体   English

使用Hooks将React类转换为功能组件。 如何解决“不受控制的输入”错误

[英]Converting React Class to Functional Components with Hooks. How to fix “uncontrolled input” error

I have the following code that I understand and it works perfectly.It is a class component. 我有以下我理解的代码,它可以完美运行,它是一个类组件。 I am trying to write a working function component version with hooks. 我正在尝试编写具有钩子的工作功能组件版本。 My refactor is giving me the infamous "uncontrolled input" error. 我的重构给了我一个臭名昭著的“不受控制的输入”错误。 I did not have the error until I used useEffect . 在使用useEffect之前,我没有出现错误。 I want to know how to fix the error. 我想知道如何解决该错误。 Thank you. 谢谢。

Old (Working) Class Component 旧(工作)类组件

class Dashboard extends Component{
    constructor(props){
      super(props)
      this.state = {
        clients: [],
        clientName:undefined
      }    

      this.clientsRef = firebase.database().ref('clients')

    }

    handleChange = (evt) => {
        this.setState({
            [evt.target.name]: evt.target.value
        });
        console.log(this.state.clientName);
    }

    addNewClient=(event,userID)=>{
        event.preventDefault()
        this.clientsRef.push({
          name: this.state.clientName,
          user_id:userID
        });

        this.setState({
              clientName:""
        })

    }


    componentDidMount() {
        this.clientsRef.on('child_added', snapshot => {
           const client = snapshot.val();
           client.key = snapshot.key;
           this.setState({ clients: [...this.state.clients, client]})
        });

        // this.state.clients.concat(client) 
     }

    /*_______________________________________________


    Add new company and associate it with a specific user ID

    _________________________________________________*/
    //


    render(){
      const {classes} = this.props;


      return(
        <Consumer>
        {(userData)=>{
           if(userData.state.user){
               console.log(userData.state.user);
           }

          return(






             <div className={classes.root}>
                  <Grid container spacing={24}>
                    <Grid item xs={12}>
                      <Paper>

                      </Paper>
                    </Grid>
                    <Grid item xs={12} sm={4}>


                    </Grid>
                    <Grid item xs={12} sm={4}>
                        <Paper className={classes.paper}>


                          <div>
                               <h1>Add new client or company</h1>
                               <form onSubmit = {(event)=>this.addNewClient(event,userData.state.userID)}>
                                 <input type="text" name="clientName" onChange = {this.handleChange} value ={this.state.clientName}/>
                                 <input type="submit" value="add client"/>
                               </form>

                                <ul> 

                                 {
                                   this.state.clients.map((val,index)=>{

                                      if(userData.state.userID === val.user_id){
                                        return <a key={index} href={`/dashboard/${userData.state.userID}/company/${val.name}/${val.key}`}> 
                                          <ListItem>{val.name}</ListItem>   
                                        </a>


                                      } 
                                   }) 
                                 }

                                 </ul>
                          </div>



                       </Paper>


                    </Grid>
                    <Grid item xs={12} sm={4}>


                    </Grid>

                  </Grid>

                  </div>


            )
          }
        }
       </Consumer>

      )
    }
}

Functional Component Version that Gives the Error. 给出错误的功能组件版本。

function Dashboard(props){

    const initialState = {
        clients: [],
        clientName:""
      }    

    const [formState,setForm] = useState(initialState);
    const clientsRef = firebase.database().ref('clients');

    function handleChange(evt){
        setForm({...formState,
            [evt.target.name]: evt.target.value
        });

        console.log(formState)

    }


    function addNewClient(event,userID){
        event.preventDefault();
        clientsRef.push({
          name: formState.clientName,
          user_id:userID
        });


        setForm({
            clientName:""
        })

    }



    function fetchData() {
        clientsRef.on('child_added', snapshot => {
           const client = snapshot.val();
           console.log(client)
           client.key = snapshot.key;
           setForm({ clients: [...formState.clients, client]})
        });


     }


    useEffect(()=>{
        fetchData()
    },[])







    /*_________________*/




      const {classes} = props;
      const userData = useContext(Context);



          return(

             <div className={classes.root}>
                  <Grid container spacing={24}>
                    <Grid item xs={12}>
                      <Paper>

                      </Paper>
                    </Grid>
                    <Grid item xs={12} sm={4}>


                    </Grid>
                    <Grid item xs={12} sm={4}>
                        <Paper className={classes.paper}>


                          <div>
                               <h1>Add new client or company</h1>
                             <form onSubmit={(event)=>addNewClient(event,userData.state.userID)} >
                               <input type="text" name="clientName" onChange = {handleChange} value = {formState.clientName}/>
                               <input type="submit" value="add client"/>
                             </form>

                            <ul> 

                              {
                                 formState.clients.map((val,index)=>{

                                    if(userData.state.userID === val.user_id){
                                      return <a key={index} href={`/dashboard/${userData.state.userID}/company/${val.name}/${val.key}`}> <ListItem>{val.name}</ListItem></a>


                                    } 
                                 }) 
                              }

                            </ul>
                          </div>
                       </Paper>

                    </Grid>
                    <Grid item xs={12} sm={4}>

                    </Grid>
                  </Grid>
              </div>


            )



}

The updator, setForm , returned from useState works differently from this.setState . 该更新器, setForm ,从返回useState从工作方式不同this.setState

While this.setState in Class Component automatically merges existing states , the hook's updator ( setForm ) doesn't automerge existing state . 虽然Class Component中的this.setState自动合并现有状态 ,但是挂钩的更新程序( setForm不会自动合并 现有状态

... However, unlike this.setState in a class, updating a state variable always replaces it instead of merging it. ...但是,与类中的this.setState不同,更新状态变量总是替换它而不是合并它。

When you set clients in fetchData , fetchData设置客户端时,

function fetchData() {
  clientsRef.on("child_added", snapshot => {
    const client = snapshot.val();
    console.log(client);
    client.key = snapshot.key;

    // 👇 
    setForm({ clients: [...formState.clients, client] });
  });
}

setForm({ clients: [...formState.clients, client] }); turns clientName into undefined . clientName变成undefined

You'd need to spread existing state (as you do with reducer or Redux) to return a new reference containing clientName , which was set to the value for input below. 您需要散布现有状态(与reducer或Redux一样),以返回包含clientName的新引用,该引用已设置为以下input的值。

<input
  type="text"
  name="clientName"
  onChange={handleChange}
  value={formState.clientName}
/>;

When you fetch data, that input field gets uncontrolled because formState.clientName is undefined. 当您获取数据时,该输入字段将uncontrolled因为formState.clientName是未定义的。

So return a new reference without clearing clientName . 因此,返回一个新引用而不清除clientName

setForm(previousForm => ({
  ...previousForm,
  clients: [...formState.clients, client]
}));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将代码从功能性 React 钩子转换为类组件 - Converting code from functional React hooks to class components 不受控制的输入 React Hooks(控制台错误) - Uncontrolled input React Hooks ( console error) 输入不受控制的React Hooks - Uncontrolled input React Hooks 我想使用 React 钩子将我的 React 类组件转换为功能组件。 它给出了如下错误 - I wanted to convert my react class component to a functional component using react hooks. it gave an error like below 使用反应挂钩 (useRef) 将 class 组件转换为功能组件—如何避免“未定义”错误 - Converting class component to functional component using react hooks (useRef)—how to avoid “undefined” error 在 react native 中将 class 组件转换为钩子形式 - Converting class components to hooks form in react native 将不受控制的组件从:类扩展到功能组件? - Convert Uncontrolled Components from : Class extends to Functional Components? React Todo App 将类组件转换为功能组件时出错 - React Todo App I get an error while converting class components to functional components 使用钩子将 React class 组件转换为功能组件:事件侦听器的问题 - Converting React class component to functional component with hooks : Problem with event listeners 如何将 React 函数式组件转换为类组件 - How to Convert React Functional Components into Class Components
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM