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

如果覺(jué)得還有點(diǎn)用汪厨,請(qǐng)您給我一個(gè)贊护戳!您的贊是我堅(jiān)持下去的動(dòng)力

環(huán)境:react 16.12.0

這里將會(huì)用類和函數(shù)組件2種方法實(shí)現(xiàn)同一目標(biāo)來(lái)對(duì)比他們的區(qū)別

目錄

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

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

案例:
我們實(shí)現(xiàn)一個(gè)子組件Input庇谆,帶有一個(gè)輸入框和一個(gè)提交按鈕
再實(shí)現(xiàn)一個(gè)父組件Form厉亏,希望當(dāng)Input組件內(nèi)用戶輸入完畢點(diǎn)提交后企巢,父組件能獲得到通知并拿到Input的值

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

  function onClick(){
    //這里就是父組件傳遞給子組件的方法丑念,子組件可以通過(guò)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>
  );
}
  • 類式組件實(shí)現(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)的方法

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

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

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

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

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

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

  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();//生成一個(gè)ref一會(huì)兒用來(lái)綁定Input子組件
  function onClick(){
    //通過(guò)ref.current可以獲取子組件內(nèi)暴露給父組件的所有對(duì)象
    refInput.current.clear();
  }

  return (
    <div>
      <Input ref={refInput} ></Input>
      <button onClick={onClick}>清除輸入框的內(nèi)容</button>
    </div>
  );
}
  • 類式組件實(shí)現(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下,對(duì)于被Form.create()的組件宝惰,需要通過(guò)<Component wrappedComponentRef={ref=>this.ref=ref} /> 來(lái)獲取到真實(shí)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的時(shí)候不會(huì)合并對(duì)象成員,我們需要手動(dòng)使用{...param,...newParam}等方式進(jìn)行合并

函數(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)對(duì)象的時(shí)候掌测,由于setState只做淺拷貝所以會(huì)出現(xiàn)問(wè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沒(méi)了

解決方案是在多層的時(shí)候?qū)⑼鈱拥膶?duì)象進(jìn)行展開(kāi)合并

 var obj = {
      objList:{
        ...this.state.objList, //展開(kāi)父級(jí)
        objB:{
          list:[5,2],
          selected:11
        }
      }
    };

    this.setState(obj);

state變化

當(dāng)我們點(diǎn)擊一個(gè)按鈕時(shí)觸發(fā)一個(gè)延時(shí)alert,時(shí)間到了打印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>
  );
}

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

類式組件

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>
      </>
    );
  }

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

如果覺(jué)得還有點(diǎn)用庙睡,請(qǐng)您給我一個(gè)贊事富!您的贊是我堅(jiān)持下去的動(dòng)力

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末技俐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子统台,更是在濱河造成了極大的恐慌雕擂,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贱勃,死亡現(xiàn)場(chǎng)離奇詭異井赌,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)贵扰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)仇穗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人戚绕,你說(shuō)我怎么就攤上這事纹坐。” “怎么了舞丛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵恰画,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我瓷马,道長(zhǎng)拴还,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任欧聘,我火速辦了婚禮片林,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘怀骤。我一直安慰自己费封,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布蒋伦。 她就那樣靜靜地躺著弓摘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪痕届。 梳的紋絲不亂的頭發(fā)上韧献,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音研叫,去河邊找鬼锤窑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嚷炉,可吹牛的內(nèi)容都是我干的渊啰。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼绘证!你這毒婦竟也來(lái)了隧膏?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嚷那,失蹤者是張志新(化名)和其女友劉穎胞枕,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體车酣,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年索绪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了湖员。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瑞驱,死狀恐怖娘摔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情唤反,我是刑警寧澤凳寺,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站彤侍,受9級(jí)特大地震影響肠缨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盏阶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一晒奕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧名斟,春花似錦脑慧、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至岩梳,卻和暖如春囊骤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背冀值。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工淘捡, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人池摧。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓焦除,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親作彤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子膘魄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345