天天看點

初入項目,JS可能遇到的問題優化以及處理方法

ES6篇

1.Array.from()

為什麼先提到Array.from(),在開發中發現數組才是最常見的一種格式,不僅是在渲染清單,表格,還是在資料請求上,都有着重要的意義。

首先,先看看Array.from()定義,它可以将一個類數組或可周遊對象轉成一個真實的數組。所謂類數組,就是我們在非箭頭函數中所屬的arguments類型等等;可周遊對象,便如Map類型等等。

使用規則為

Array.from(arrayLike, mapFn, thisArg)
/*
arrayLike: 必選,1、類數組(argumentg)2、可疊代對象(set,map)。
mapFn: 可選,相當于Array.from(arrayLike).map(mapFn, thisArg)。
thisArg: 可選,執行回調函數mapFn時候的this對象。非常有用,利于解耦。可以把被處理的資料和對象分離,thisArg中定義處理函數handle,用來在mapFn中傳回調用handle之後的結果。
*/      

功能上他能實作什麼呢?

1.将string類型轉為數組

const str = 'wangjingyu';
const arr = Array.from(str);
console.log(arr);
// (10) ["w", "a", "n", "g", "j", "i", "n", "g", "y", "u"]      

2.将Set類型轉為數組

const set = new Set([1,2,3]);
const arr = Array.from(set);
console.log(arr);
// (3) [1, 2, 3]      

3.将Map類型轉為數組

const map = new Map([[1,2,3],[4,5,6]]);
const arr = Array.from(map);
console.log(arr);
// [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]      

4.将類數組arguments轉為數組

const fun = function(a,b,c){
    const args = Array.from(arguments);
    console.log(args)
}
fun(1,2,3)
// [ 1, 2, 3 ]      

5.使用第二個參數構造函數傳回新數組

const newArr = Array.from([1,2,3], value => value * value);
console.log(newArr);
// [ 1, 4, 9 ]
const lenArr = Array.from({length: 10}, (v, i) => i + 10);
console.log(lenArr);  
// [10, 11, 12, 13, 14,15, 16, 17, 18, 19]      

6.數組去重合并

const arr_a = [1,2,3];
const arr_b = [2,3,4];
const arr_c = [3,4,5];
const combine = function(a,b,c){
    const arrAll = [].concat.apply([],arguments);
    console.log(Array.from(new Set(arrAll)))
}
combine(arr_a,arr_b,arr_c);
// [ 1, 2, 3, 4, 5 ]      

7.擷取數組對象中的某指定屬性的所有值

const cities = [
    { name: 'Paris', visited: 'no' },
    { name: 'Lyon', visited: 'no' },  
    { name: 'Marseille', visited: 'yes' },  
    { name: 'Rome', visited: 'yes' },  
    { name: 'Milan', visited: 'no' },  
    { name: 'Palermo', visited: 'yes' },  
    { name: 'Genoa', visited: 'yes' },  
    { name: 'Berlin', visited: 'no' },  
    { name: 'Hamburg', visited: 'yes' },  
    { name: 'New York', visited: 'yes' }
 ];
console.log(Array.from(cities, ({name}) => name))
// (10) ["Paris", "Lyon", "Marseille", "Rome", "Milan", "Palermo", "Genoa", "Berlin", "Hamburg", "New York"]      

8.采用第三個參數進行資料和對象抽離

const arr = [1,2,3,4,5];
const obj = {
    double: x => x * 2,
    triple: x => x * 3,
    sqrt: x => x * x,
}
console.log(Array.from(arr, function(x){ return this.triple(x) }, obj))
// [ 3, 6, 9, 12, 15 ]      

通過Array.from()方法,我們可以使用更少的代碼完成我們需要做到的功能。

2.解構原始資料

我們大多數在使用對象時候,會将一個大對象分出小的屬性,屬性值來使用,其中,我們可能會覺得某一個對象裡面的屬性值太多,而我們隻需要其中的若幹個,這裡我們就可以使用這種方法來做解構。

const rawUser = {  
    name: 'WangJingyu',
    surname: 'Jack',  
    email: '[email protected]',  
    displayName: 'WhmJack',  
    joined: '2021-03-04',  
    image: 'github',  
    followers: 1000
}
let user = {}, userDetails = {};
({name:user.name,surname:user.surname,...userDetails} = rawUser)
console.log(user,userDetails)
// { name: 'WangJingyu', surname: 'Jack' }  
// {
//   email: '[email protected]',
//   displayName: 'WhmJack',
//   joined: '2021-03-04',
//   image: 'github',
//   followers: 1000
// }      

這樣我們就可以把自己需要的某幾個對象屬性取出來來使用了。

3.動态屬性名

在ES5時代,我們擷取屬性一般有兩種方式,要不是直接.xxx,要不就是定義變量名去通過[]擷取:

const person = {
    name : 'wjy',
    age : 23,
}
const attName = 'name';
console.log(person[attName],person.name)  
// wjy wjy      

我們可以把attName作為變量名,但是隻能在對象之外對他做指派操作,并不能做到讓person對象的屬性動态變化。可能有的人要說,那我把那麼當成一個變量就好了,就比如:

const attName = 'name';
const person = {
    attName : 'wjy',
    age : 23,
}
console.log(person[attName],person.attName)  
// undefined wjy      

好像不太行的亞子,我們來看看原因,person.attName擷取的屬性就是字元串attName,是以可以擷取到,而person[attName]擷取的則是person.name,但是我們的attName在person對象裡隻是一個字元串,并不是一個變量,是以擷取不到,那麼怎麼辦呢?

ES6中提出了把屬性名用[]包起來的方法,在括号中就可以使用前面定義的變量了。就是:

const attName = 'sex';
const person = {
    name : 'wjy',
    [attName] : 'male',
    age : 23,
}
console.log(person[attName])
// male      

這樣我們就可以動态設定對象的屬性名了。  

4.symbol的對象使用

作為ES6新提出的變量類型,雖然symbol屬性已經出來很久了,但是很多時候我們還是很少使用它,這裡提到一種小小的用法,僅僅作為抛磚,更多的方法等着各位dalao來補充擴充。

對于一個已經存在的對象,裡面可能存在一個屬性key,名字暫且為'id',在多人開發時候可能會有其他人也對此對象做了内部屬性命名為id的操作,或者說他繼承了這個對象,并且對這個對象做了重寫,那麼這樣會導緻這個對象的id被覆寫。進而出現一些問題。這個時候就可以讓symbol大顯身手了。

const custId = Symbol.for('id');
const obj = {
    [custId] : '0100110100',
    'id' : '23322232',
    'iq' : '150',
};
console.log(obj);
// { id: '23322232', iq: '150', [Symbol(id)]: '0100110100' }      

那麼問題來了,我們怎麼把他取出來呢,如果采用正常的for循環,結果是這樣的:

for(let [key,value] of Object.entries(obj)){
    console.log('let of',key,value)
}
// let of id 23322232
// let of iq 150      

确實不太行,我們可以用symbol的api去擷取:

Object.getOwnPropertySymbols(obj).forEach((item) => {
    console.log(obj[item])
})
// 0100110100      

确實是可以的,但是如果我們想for循環整體obj呢,這時候可以使用反射Reflect的相關api:

Reflect.ownKeys(obj).forEach(item => {
    console.log(obj[item])
})
// 23322232
// 150
// 0100110100      

這樣我們就可以把值取出來了,并且達到了我們的效果。

分支優化篇

這一塊主要是針對if else做的一個優化方法政策的整理總結,在做項目中,難免會出現越來越多的判斷情況,而我們也需要根據這些判斷數值來做選擇,兩個三個分支選擇還好,如果選擇多了起來,那麼我們可能就會出現這樣的情況:

const ifOperation = (status) => {
  if(status === 1){
    consoleLog('one');
    consoleRun('oneEvent');
  } else if(status === 2){
    consoleLog('two');
    consoleRun('TwoEvent');
  } else if(status === 222){
    consoleLog('two');
    consoleRun('TwoEvent');
  } else if(status === 3){
    consoleLog('three');
    consoleRun('ThreeEvent');
  } else if(status === 4){
    consoleLog('four');
    consoleRun('FourEvent');
  } else {
    consoleLog('other');
    consoleRun('OtherEvent');
  }
}      

雖然隻有六個分支,但是已經看起來臃腫不堪了,可能我們可以把某一個else if變得厚重一下?

const ifOperation = (status) => {
  if(status === 1){
    consoleLog('one');
    consoleRun('oneEvent');
  } else if(status === 2 || status === 222){
    consoleLog('two');
    consoleRun('TwoEvent');
  } else if(status === 3){
    consoleLog('three');
    consoleRun('ThreeEvent');
  } else if(status === 4){
    consoleLog('four');
    consoleRun('FourEvent');
  } else {
    consoleLog('other');
    consoleRun('OtherEvent');
  }
}      

看起來可能好一些,不過更多的人應該會選擇switch case,那麼它就會變成:

const switchOperation = (status) => {
  switch(status){
    case 1:
      consoleLog('one');
      consoleRun('oneEvent');
      break;
    case 2:
    case 222:
      consoleLog('two');
      consoleRun('TwoEvent');
      break;
    case 3:
      conosleLog('three');
      consoleRun('ThreeEvent');
      break;
    case 4:
      consoleLog('four');
      consoleRun('FourEvent');
      break;
    default:
      consoleLog('other');
      consoleRun('OtherEvent');
      break;
  }
}      

在工作中其實這種已經是我們的常态了,不過我們可以更進一步,借助其他資料類型幫助我們簡化代碼,比如用個對象存儲if else的各種情況:

const obj = {
  1 : ['one','oneEvent'],
  2 : ['two','TwoEvent'],
  3 : ['three','ThreeEvent'],
  4 : ['four','FourEvent'],
  222 : ['two','TwoEvent'],
  'default' : ['other', 'OtherEvent']
}
const consoleLog = (status) => {
  console.log(status);
}
const consoleRun = (status) => {
  console.log(status);
}
const objOperation = (status) => {
  let operation = obj[status] || obj['default'];
  consoleLog(operation[0]);
  consoleRun(operation[1])
}
objOperation('222')      

這樣就清爽很多了,比如我在做播放錄音點選修改倍速時候可以寫的更加精簡,比如:

// 設定點選修改倍速條件
const obj = {
    1: [1.5],
    1.5: [2],
    2: [0.5],
    0.5: [1],
};
const objOperation = (status) => {
    const operation = obj[status];
    const speedChoose = operation[0];
    setSpeed(speedChoose);
};
objOperation(speed);      

當然,如果你不想用Object表示,你還可以用Map來表示呀:

const map = new Map([
  [1 , ['one','oneEvent']],
  [2 , ['two','TwoEvent']],
  [3 , ['three','ThreeEvent']],
  [4 , ['four','FourEvent']],
  [222 , ['two','TwoEvent']],
  ['default' , ['other', 'OtherEvent']]
])
const consoleLog = (status) => {
  console.log(status);
}
const consoleRun = (status) => {
  console.log(status);
}
const mapOperation = (status) => {
  let operation = map.get(status) || map.get('default');
  consoleLog(operation[0]);
  consoleRun(operation[1])
}
mapOperation(222)      

不過,在Object對象和Map對象都能使用的情況下,我們優先選擇哪種呢?

1.Object一般是有自己的原型的,是以每個對象都是有一個prototype鍵

2.Object對象的鍵一般可以是數字類型,字元串類型以及symbol類型,但是一個Map的鍵可以是任意類型,使用起來更為友善

3.對于擷取鍵值對個數之類,Map可以直接用map.size擷取,而Object則需要先用Object.key()擷取所有的鍵數組,然後再去擷取length

現在我們可能需要做更多的事情,比如我們現在有兩層判斷了,不僅僅需要判斷條件a,還要判斷條件b,比如:

/*
 * param {number} status 表示狀态
 * param {string} roommate 表示舍友名稱
*/
const ifOperation = (status,roommate) => {
    if(roommate === 'ly'){
        if(status === 1){
            consoleLog('lyone');
        } else if(status === 2){
            consoleLog('lytwo');
        } else if(status === 3){
            consoleLog('lythree');
        } else if(status === 4){
            consoleLog('lyfour');
        } else {
            consoleLog('sbother');
        }
    } else if(roommate === 'wjy'){
        if(status === 1){
            consoleLog('wjyone');
        } else if(status === 2){
            consoleLog('wjytwo');
        } else if(status === 3){
            consoleLog('wjythree');
        } else if(status === 4){
            consoleLog('wjyfour');
        } else {
            consoleLog('sbother');
        }
    } else {
        consoleLog('sbother');
    }
}      

這。。。看起來也太長了,如果說單層判斷還可以接受,那麼這種長度的判斷,看起來确實有點難受,不過這種情況也很普遍,可能我遇到了這樣的問題,也會首先采用這種模式去進行代碼的編寫。但是我們要知道,一旦判斷層級多了一級,那麼我們增加的條件就是2(n)倍,這時候要怎麼去寫呢?我們仍然可以采用map或者object去處理:

const map = new Map([
    ['ly_1', () => {consoleLog('lyone');consoleRun('ly_1')}],
    ['ly_2', () => {consoleLog('lytwo');consoleRun('ly_2')}],
    ['ly_3', () => {consoleLog('lythree');consoleRun('ly_3')}],
    ['ly_4', () => {consoleLog('lyfour');consoleRun('ly_4')}],
    ['wjy_1', () => {consoleLog('wjyone');consoleRun('wjy_1')}],
    ['wjy_2', () => {consoleLog('wjytwo');consoleRun('wjy_2')}],
    ['wjy_3', () => {consoleLog('wjythree');consoleRun('wjy_3')}],
    ['wjy_4', () => {consoleLog('wjyfour');consoleRun('wjy_4')}],    
    ['default', () => {consoleLog('sbother');consoleRun('other roommate')}],
])
const mapOperation = (status,roommate)=>{
  let mapAction = map.get(`${roommate}_${status}`) || map.get('default')
  mapAction.call(this)
}
mapOperation(1,'wjy')
// wjyone
// wjy_1      

用Object來寫也是一樣,如下:

const obj = {
    'ly_1': () => {consoleLog('lyone');consoleRun('ly_1')},
    'ly_2': () => {consoleLog('lytwo');consoleRun('ly_2')},
    'ly_3': () => {consoleLog('lythree');consoleRun('ly_3')},
    'ly_4': () => {consoleLog('lyfour');consoleRun('ly_4')},
    'wjy_1': () => {consoleLog('wjyone');consoleRun('wjy_1')},
    'wjy_2': () => {consoleLog('wjytwo');consoleRun('wjy_2')},
    'wjy_3': () => {consoleLog('wjythree');consoleRun('wjy_3')},
    'wjy_4': () => {consoleLog('wjyfour');consoleRun('wjy_4')},  
    'default': () => {consoleLog('sbother');consoleRun('other roommate')},
}
const objOperation = (status,roommate)=>{
  let objAction = obj[`${roommate}_${status}`] || obj['default']
  objAction.call(this)
}
objOperation(1,'wjy')
// wjyone
// wjy_1      

這類方法的核心就是把兩個條件拼接成一個unique的字元串,然後将拼接的字元串作為主鍵,來進行對應的函數處理,從原理上講,條件層級越多,這個方法就越簡單越省事。當然,可能有些同學覺得這樣不夠規範,覺得下劃線不正規,也可以采用對象方式。

const map = new Map([
    [{status:'1',roommate:'ly'}, () => {consoleLog('lyone');consoleRun('ly_1')}],
    [{status:'2',roommate:'ly'}, () => {consoleLog('lytwo');consoleRun('ly_2')}],
    [{status:'3',roommate:'ly'}, () => {consoleLog('lythree');consoleRun('ly_3')}],
    [{status:'4',roommate:'ly'}, () => {consoleLog('lyfour');consoleRun('ly_4')}],
    [{status:'1',roommate:'wjy'}, () => {consoleLog('wjyone');consoleRun('wjy_1')}],
    [{status:'2',roommate:'wjy'}, () => {consoleLog('wjytwo');consoleRun('wjy_2')}],
    [{status:'3',roommate:'wjy'}, () => {consoleLog('wjythree');consoleRun('wjy_3')}],
    [{status:'4',roommate:'wjy'}, () => {consoleLog('wjyfour');consoleRun('wjy_4')}],    
    ['default', () => {consoleLog('sbother');consoleRun('other roommate')}],
])
const mapOperation = (status,roommate)=>{
  let mapAction = [...map].filter(([key,value])=>(key.roommate === roommate && key.status === status))
  if(mapAction.length === 0){
    mapAction = map.get('default');
    mapAction.call(this);
  } else {
    mapAction.forEach(([key,value])=>value.call(this))      
  }
}      

這樣我們就可以看到Object和Map的一個主要差別了,在使用Map類型時候我們可以選擇通過對象來做為key值。當然還有可能出現這種情況,比如同一個方法在某幾個條件中都被同時使用,并且傳了相同的參數比如:

const map = new Map([
    [{status:'1',roommate:'ly'}, () => {consoleRun('ly')}],
    [{status:'2',roommate:'ly'}, () => {consoleRun('ly')}],
    [{status:'3',roommate:'ly'}, () => {consoleRun('ly')}],
    [{status:'4',roommate:'ly'}, () => {consoleRun('ly4')}],
    ['default', () => {consoleRun('other roommate')}],
])      

這個時候就可以采用正則去進行了,把前四條作為一個整體去比對正則,比如:

const map = () => {
    return new Map([
        [/^ly_[1,4]$/, () => consoleRun('ly')],
        [/^default$/, () => {consoleLog('sbother');consoleRun('other roommate')}],
    ])  
}      

通過正則去做比對,當然這也是由于Map類型可以将各種類型作為key。下面舉一個更為具體的小例子,由于本人能力有限可能有很多沒想到的地方,是以寫出的代碼可能還是有些備援,歡迎大家提意見,先看看古老的if else方式:

const ifOperation = (status,roommate) => {
    if(roommate === 'ly'){
        if(status === 1){
            consoleLog('lyone');
        } else if(status === 2){
            consoleLog('lytwo');
        } else if(status === 3){
            consoleLog('lythree');
        } else if(status === 4){
            consoleLog('lyfour');
        } else {
            consoleLog('lyother');
        }
    } else if(roommate === 'wjy'){
        if(status === 1){
            consoleLog('wjyone');
        } else if(status === 2){
            consoleLog('wjytwo');
        } else if(status === 3){
            consoleLog('wjythree');
        } else if(status === 4){
            consoleLog('wjyfour');
        } else {
            consoleLog('wjyother');
        }
    } else {
        consoleLog('sbother');
    }
}      

這裡可以發現,和前面隻有一點不同,就是三個else分别是三個不同的條件,這樣用default處理就要分成三部分,這裡采用正則試試看咯:

const map = () => {
    return new Map([
        [/^ly_1$/, () => consoleLog('lyone')],
        [/^ly_2$/, () => consoleLog('lytwo')],
        [/^ly_3$/, () => consoleLog('lythree')],
        [/^ly_4$/, () => consoleLog('lyfour')],
        [/^ly_.*$/, () => consoleLog('lyother')],
        [/^wjy_1$/, () => consoleLog('wjyone')],
        [/^wjy_2$/, () => consoleLog('wjytwo')],
        [/^wjy_3$/, () => consoleLog('wjythree')],
        [/^wjy_4$/, () => consoleLog('wjyfour')],    
        // [/^ly_((?![1-4]{1}[\S]{0}).)*|^ly_[1-4]{2,}$/g, () => consoleLog('lyother')],
        [/^wjy_.*$/, () => consoleLog('wjyother')],
        [/^.*.*$/, () => consoleLog('sbother')],
    ])
}
const mapArray = new Map([
    [2, (operation) => operation.pop()],
    [3, (operation) => {
        // console.log(operation);
        operation.pop();    
        operation.pop();
    }],
    ['default', () => {}],
])
const mapOperation = (status,roommate) => {
    let operation = [...map()].filter(([key,value]) => {
        if(key.test(`${roommate}_${status}`)){
            return value;            
        }
    });
    let operationArr = mapArray.get(operation.length) || mapArray.get('default');
    operationArr.call(this,operation);
    operation.forEach(([key,value]) => value.call(this))
}
mapOperation(10000,'ly1')      

原理很簡單,這裡我使用了兩層判斷邏輯,首先是進行正規表達式的編寫,由于有三個else,是以可能我們需要三個default,從正則角度來說就是任意字元了,這裡比對會出現三種可能性,如果沒有比對到,那麼隻會存在一種可能為```[ [ /^.*.*$/, [Function (anonymous)] ] ]```,如果roommate正确比對,而status沒有正确比對,那麼會出現兩種情況,我将一定比對的可能在數組存在最後就可以将其彈出,就可以獲得真實比對正則,另外如果完全正确,那麼三個正則都會成功比對,我們就需要彈出最後兩個,隻取第一個。而彈出正則又是一個if else,我就放到了另一個map中,進而實作需求。

React hook篇

來到公司一開始做了一個前後端聯調的小項目,首先使用的就是React hook,那個時候還是不夠熟悉,後來參加其他項目又用了16.8之前的生命周期函數,最近重歸hook,發現項目中很多人都把元件的狀态存在了model裡,不過我還是覺得父子元件傳值傳函數這類基礎要拿出來整理一下,恰巧最近事情不多,就整理一下。

整體上分成四類:

1.父元件傳值給子元件
2.父元件傳方法給子元件
3.子元件傳值給父元件
4.子元件傳方法給父元件

最簡單的最常用的就是父元件傳值給子元件,一般采用props傳值,我寫了一個最基本的例子:

父元件:

import React,{useState} from 'react';
import {Button} from 'antd';
import styles from './HomePage.less';
import Children from './components/Children';
const HomePage = () => {
  const [value,setValue] = useState('first');
  return (
    <div className={styles.root}>
      <Button onClick={() => {
        setValue('second')
      }}>change</Button>
      <Children value={value} />
    </div>
  )
}
export default HomePage;      

子元件:

import React from "react";
import PropTypes from "prop-types";
import styles from "./Children.less";
const Children = (props) => {
  const { value } = props;
  return (
    <div className={`${styles.root}`} >
      {value}
    </div>
  );
};
Children.propTypes = {
  value:PropTypes.string
};
Children.defaultProps = {
  value:''
};
export default Children;      

這是最簡單的,也是最常用的,基本任何一個項目都會用到,也是我們一般抽出業務元件最基本的類型。

2.父元件傳方法給子元件/子元件傳值給父元件

個人了解這兩類其實是一類,隻是一個大的集合和一個小的集合的差別,就是說父元件傳方法給子元件是一個大的子產品,而恰巧這個子產品中囊括了子元件傳值給父元件這一個功能。舉個例子:

import React,{useState} from 'react';
import styles from './HomePage.less';
import Children from './components/Children';
const HomePage = () => {
  const [value, setvalue] = useState('')
  const method = (val) => {
    setvalue(val);
  }
  return (
    <div className={styles.root}>
      <Children method={method} />
      {value}
    </div>
  )
}
export default HomePage;      

子元件:

import React from "react";
import PropTypes from "prop-types";
import {Button} from 'antd';
import styles from "./Children.less";
const Children = (props) => {
  const { method } = props;
  return (
    <div className={`${styles.root}`} >
      <Button onClick={() => {
        method('children')
      }}>children</Button>
    </div>
  );
};
Children.propTypes = {
  method:PropTypes.func
};
Children.defaultProps = {
  method:() => {}
};
export default Children;      

這裡的例子我寫的最基本,從子元件傳值給父元件的角度上講,就是子元件傳了一個value給父元件,讓父元件帶它去做他該做的事。那麼,從父元件傳方法給子元件上講,就是父元件傳了一個叫做method的方法給了子元件,這個方法裡,父元件想幹什麼就幹什麼,隻需要子元件去調用就好了。當然,他們最天衣無縫的配合就是父元件已經把方法寫好了,隻需要子元件傳值來讓父元件方法正常運轉就好了,perfect!

3.子元件傳方法給父元件

其實掌握了前面兩種基礎方法,在大多數項目已經夠用了,簡單的元件傳值用props,以及基于他的派生政策,複雜的可以在model裡存值去做傳遞,不過偶爾我們也需要在父元件中調用子元件的方法。我之前就遇到了這麼個問題,寫了一個大元件内容過多,我需要把他提出來,然後發現我使用了太多的useState,而且把子元件提出來後,發現事件是父元件的事件,但是需要修改子元件的state狀态,于是我就把修改子元件state的地方封裝成一個函數,供父元件去調用就好了。這裡舉個最簡單的例子:

import React,{useRef} from 'react';
import styles from './HomePage.less';
import {Button} from 'antd';
import Children from './components/Children';
const HomePage = () => {
  const childRef = useRef<any>();
  return (
    <div className={styles.root}>
      <Children cRef={childRef} />
      <Button onClick={() => {
        childRef.current.childrenMethod();
      }}>click</Button>
    </div>
  )
}
export default HomePage;      

子元件

import React,{useImperativeHandle,useState} from "react";
import PropTypes from "prop-types";
import {Button} from 'antd';
import styles from "./Children.less";
const Children = (props) => {
  const { cRef } = props;
  const [value, setvalue] = useState('')
  useImperativeHandle(cRef,() => ({
      childrenMethod:() => {
        setvalue('children');
      }
    }),
  );
  return (
    <div className={`${styles.root}`} >
      {value}
    </div>
  );
};
Children.propTypes = {
  cRef:PropTypes.object
};
Children.defaultProps = {
  cRef:{}
};
export default Children;      

說起來useRef也是很神奇的,在這裡,我們的子元件暴露給父元件的方法是childrenMethod,并且做了一個指代,父元件通過這個指代擷取到子元件方法,進而進行調用。當然這裡我隻是針對hook做的分析,如果是類元件裡,就要使用createRef了。需要了解的也可以看看這個文章,個人感覺還不錯:

https://zhuanlan.zhihu.com/p/269580627

到這裡,對于父子元件傳值,傳函數都做了一個介紹和描述,作為新上手項目的同學來說,可以從我這個基礎例子出發,去感受React程式設計更為神秘的地方。

結語

之前在分享React生命周期之後,就想對JS一些我用到的以及一些想要在接下來項目中用到的小知識點做一些整理,當然我接觸項目時間也不久,暫時就統計到了這些,後續有新的收獲,還會持續統計更新。

繼續閱讀