React類組件和函數(shù)組件區(qū)別對比使用

如果覺得還有點用,請您給我一個贊!您的贊是我堅持下去的動力

環(huán)境:react 16.12.0

這里將會用類和函數(shù)組件2種方法實現(xiàn)同一目標來對比他們的區(qū)別

目錄

  • 子組件向父組件通信的方法(如何調(diào)用父組件方法)
  • 父組件向子組件通信的方法(如何調(diào)用子組件方法)
  • setState對象成員合并問題
  • state變化

子組件向父組件通信,調(diào)用父組件方法

案例:
我們實現(xiàn)一個子組件Input,帶有一個輸入框和一個提交按鈕
再實現(xiàn)一個父組件Form,希望當Input組件內(nèi)用戶輸入完畢點提交后,父組件能獲得到通知并拿到Input的值

  • 函數(shù)式組件實現(xiàn)方式
    函數(shù)式子組件 Input.js
//寫一個Input組件,作為子組件用
function Input(props){
  //用于存放輸入的值
  const [state, setState] = useState({inputValue:''});

  function onClick(){
    //這里就是父組件傳遞給子組件的方法,子組件可以通過props直接調(diào)用
    props.onSubmit(state.inputValue);
  }

  function onInput(v){
    setState({inputValue:v.target.value});
  }

  return (
    <div>
      <input value={state.inputValue} onChange={onInput}  type="text" ></input>
      <button onClick={onClick}>提交</button>
    </div>
  );
}

export default Input;

函數(shù)式父組件 Form.js

import React from 'react';
import Input from './Input.js';

function Form(props){
  //提供給子組件使用
  function onSubmit(value){
    console.log(`子組件提交啦,用戶輸入的是:${value}`)
  }

  return (
    <div>
      <Input onSubmit={onSubmit} ></Input>
    </div>
  );
}
  • 類式組件實現(xiàn)方式
    類式子組件 Input.js
class Input_Class extends React.Component{

  constructor(props){
    super(props);
    this.state = {
      inputValue:''
    }
  }

  onClick=()=>{
    this.props.onSubmit(this.state.inputValue);
  }

  onInput=(v)=>{
    this.setState({inputValue:v.target.value});
  }

  render(){
    return (
      <div>
        <input value={this.state.inputValue} onChange={this.onInput} type="text" ></input>
        <button onClick={this.onClick}>提交</button>
      </div>
    );
  }
}
export default Input_Class;

類式父組件 Form.js


class Form_Class extends React.Component{
  constructor(props){
    super(props);
    this.state = {}
  }

  onSubmit =(value)=>{
    console.log(`子組件提交啦,用戶輸入的是:${value}`)
  }

  render(){
    return (
      <div>
          <Input onSubmit={this.onSubmit} ></Input>
      </div>
    );
  }

}

父組件向子組件通信,調(diào)用子組件內(nèi)的方法

案例:
我們實現(xiàn)一個Input組件作為子組件
實現(xiàn)一個Form組件作為父組件
父組件內(nèi)通過按鈕點擊后需要調(diào)用子組件Input內(nèi)的clear()方法來清空輸入框

實現(xiàn)方法如下:

  • 函數(shù)式組件實現(xiàn)方式
    子組件 Input.js
import React, { useState,useImperativeHandle,forwardRef }  from 'react';

//寫一個Input組件,作為子組件用
function Input(props,ref){
  //用于存放輸入的值
  const [state, setState] = useState({inputValue:''});

  //用于清除輸入框里的內(nèi)容
  function clear(){
    setState({inputValue:''});
  }

  //這里就是用來暴露給ref.current下面的東西
  useImperativeHandle(ref, () => ({
    //我們暴露給ref.current.clear()這么一個方法,用來調(diào)用內(nèi)部的clear()
    clear: () => {
      clear();//這里調(diào)用內(nèi)部的clear,當然你可以直接將clear的實現(xiàn)體寫在這里
    }
  }));

  return (
    <div>
      <input value={state.inputValue} onChange={onInput}  type="text" ></input>
    </div>
  );
}
Input= forwardRef(Input);
export default Input;

父組件 Form.js

import React, { useState,useRef } from 'react';
import Input from './Input.js';

function Form(props){
  const refInput=  useRef();//生成一個ref一會兒用來綁定Input子組件
  function onClick(){
    //通過ref.current可以獲取子組件內(nèi)暴露給父組件的所有對象
    refInput.current.clear();
  }

  return (
    <div>
      <Input ref={refInput} ></Input>
      <button onClick={onClick}>清除輸入框的內(nèi)容</button>
    </div>
  );
}
  • 類式組件實現(xiàn)方式
    子組件 Input.js -- 如果子組件是類式組件,則不需要做任何特殊處理
class Input_Class extends React.Component{

  constructor(props){
    super(props);
    this.state = {
      inputValue:''
    }
  }

  onClick=()=>{
    this.props.onSubmit(this.state.inputValue);
  }

  clear=()=>{
    this.setState({inputValue:''});
  }
  onInput=(v)=>{
    this.setState({inputValue:v.target.value});
  }
  render(){
    return (
      <div>
        <input value={this.state.inputValue} onChange={this.onInput}  style={styleInput} type="text" ></input>
        <button onClick={this.onClick} style={styleBtn}>提交</button>
      </div>
    );
  }
}

父組件 Form.js

需要注意在antd2-3下,對于被Form.create()的組件,需要通過<Component wrappedComponentRef={ref=>this.ref=ref} /> 來獲取到真實ref


class Sortable_Class extends React.Component{
  constructor(props){
    super(props);
    this.state = {}
    this.refInput = React.createRef();
  }

  btnSubmit=(value)=>{
    console.log(`input value:${value}`);
  }
  btnClearInput=()=>{
    this.refInput.current.clear();
  }

  render(){
    return (
      <div>
          <Input ref={this.refInput} onSubmit={this.btnSubmit} ></Input>
          <button onClick={this.btnClearInput}>清空輸入框</button>
      </div>
    );
  }

}

setState

在函數(shù)式組件中,setState的時候不會合并對象成員,我們需要手動使用{...param,...newParam}等方式進行合并

函數(shù)式組件


function Counter() {
  const [param,setParam] = useState({a:1,b:2})

  useEffect(() => {
    setParam({b:3});// 解決方案: setParam( {...param,...{b:3}} )
  },[]); 
  
  return (
    <>
      param:{JSON.stringify(param)}
    </>
  );
}

渲染輸出param:{b:3}

類式組件

class CounterClass extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      a:1,
      b:2,
    }
  }
    
  componentDidMount() {
    this.setState({b:3});
  }

  render(){
    return (
      <>
        param:{JSON.stringify(this.state)}
      </>
    );
  }
}

渲染輸出param:{a:1,b:3}

但是如果遇到多層結(jié)構(gòu)對象的時候,由于setState只做淺拷貝所以會出現(xiàn)問題
 this.state = {
      objList: {
        objA: {
          list: [],
          selected: 0,
        },
        objB: {
          list: [],
          selected: 1,
        },
      }
    }

var obj = {
      objList:{
        objB:{
          list:[5,2],
          selected:11
        }
      }
    };
this.setState(obj);

這里setState后的結(jié)果是 {"objList":{"objB":{"list":[5,2],"selected":11}}} ,objA沒了

解決方案是在多層的時候?qū)⑼鈱拥膶ο筮M行展開合并

 var obj = {
      objList:{
        ...this.state.objList, //展開父級
        objB:{
          list:[5,2],
          selected:11
        }
      }
    };

    this.setState(obj);

state變化

當我們點擊一個按鈕時觸發(fā)一個延時alert,時間到了打印count的值

函數(shù)式組件

function Counter() {
  const [count,setCount] = useState(0);
  //const countRef = useRef();
  //useEffect(()=>{countRef.current=count});

  function handleClick(count) {
    setTimeout(() => {
      alert('You clicked: ' + count);
      //alert('You clicked:' + countRef.current);
    }, 3000);
  }

  return (
      <div>
        <p>{count}</p>
        <button onClick={() => setCount(count + 1)}>
          Click me
        </button>
        <button onClick={handleClick}>
          Click Show Counter
        </button>
      </div>
  );
}

加入點擊Click Show Counter后點擊3下Click me,則輸出結(jié)果為: 0
這是由于handleClick調(diào)用時,count以當時的值存在閉包內(nèi),所以延時后打印的值任是0,解決方法為使用 useRef,代碼片段中注釋的部分打開

類式組件

export class CounterClass extends React.Component{
  constructor(props){
    super(props);
    this.state = {count:0}
  }

  handleClick=()=>{
    setTimeout(() => {
      alert('You clicked: ' + this.state.count);
    }, 3000);
  }

  render(){
    return (
      <>
        <p>{this.state.count}</p>
        <button onClick={() => this.setState({count:this.state.count+1})}>
          Click +1
        </button>
        <button onClick={this.handleClick}>
          Click Show Counter
        </button>
      </>
    );
  }

加入點擊Click Show Counter后點擊3下Click me,則輸出結(jié)果為: 3

如果覺得還有點用,請您給我一個贊!您的贊是我堅持下去的動力

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容