如果覺得還有點用,請您給我一個贊!您的贊是我堅持下去的動力
環(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
如果覺得還有點用,請您給我一個贊!您的贊是我堅持下去的動力