如果覺(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)力