React 組件之間的傳值
React遵循單向傳輸原則,所以儘量不要使用雙向傳值,容易導致循環更新問題。同時應該在創造組件時思考組件是否需要狀態管理,如果不需要使用函數式聲明更佳!
父向子傳值
父向子傳值起始比較簡單,主要考慮向下傳值是否會使得父組件中的狀態過於繁雜,影響頁面性能。
- 最簡單的向子傳值
- 父組件- Father Component
import { Component } from "react";
import PropTypes from "prop-types";
export default class Father extends Component {
constructor() {
super();
this.state = {
name:"STEPHEN LING",
}
}
render() {
const { name } = this.state;
return(
<Child fahterName={name}/>
)
}
}
- 子組件- Child Component
import { Component, Fragment } from "react";
import PropTypes from "prop-types";
export default class Child extends Component {
constructor() {
super();
this.props = {
fatherName:PropTypes.string.isRequired,
}
this.state = {
name:"stephen ling"
}
}
onChangeFatherName = () => {
const { onChangeFatherName } = this.props;
onChangeFatherName();
}
render() {
const { fatherName } = this.props;
const { name } = this.state;
return(
<Fragment>
<h1>我的父親:{fatherName},我:{name}</h1>
<button onClick={this.onChangeFatherName}>給我父親改個名字</button>
</Fragment>
)
}
}
總結: 將父組件的值直接通過props傳入子組件,子組件直接使用該值即可。
子向父傳值
子向父傳值也同時非常常見。
1.由子組件的事件觸發,在觸發的函數體中調用父組件傳入的方法,將子組件裏的值傳入即可。
- 父組件
import { Component, Fragment } from "react";
export default class Father extends Component {
constructor() {
super();
this.state = {
name:"STEPHEN LING",
};
};
changeMyName = newName => {
this.setState({
name: newName,
});
};
render() {
const { name } = this.state;
return(
<Fragment>
<h1>{this.state.name}</h1>
<Child onChangeFatherName={this.changeMyName}/>
</Fragment>
)
}
}
- 子組件
import { Component, Fragment } from "react";
import { Button, Input } from "antd";
export default class Child extends Component {
handleChange = value => {
this.setState({
name:e.target.value,
});
};
onChangeFatherName = () => {
const { onChangeFatherName } = this.props;
onChangeFatherName(this.state.name);
};
render() {
const { fatherName } = this.props;
const { name } = this.state;
return(
<Fragment>
<Input htmlype="text" placeholder="請輸入父親的名字." value={this.state.name} onChange={this.handleChange}/>
<Button onClick={this.onChangeFatherName}>給我父親改個名字</button>
</Fragment>
)
}
}
總結: 將父組件的改變狀態的方法傳入子組件的props,綁定給子組件中的某些觸發事件譬如按鈕的點擊,輸入框輸入等等,得到子組件的值或狀態或動作再調用父組件的方法得到子組件中的值。
兄弟間傳值
兄弟間傳值由於沒有任何嵌套關係,所以結合上述兩種情況,很容易想到將需要共享的值和方法使用上述的方法傳至共同的父組件,由父組件再傳入。
建議使用react-redux或者dva框架,瞭解不多,剛剛研究。
dva 方式
- 兄弟組件1
import { Component, Fragment } from "react";
import { Connect } from 'dva';
@connect(({ name })=>({
name,
}))
export default export default class Bro1 extends Component {
constructor() {
super();
};
handleChange = e => {
const { dispatch } = this.props;
dispatch({
type:"name/updateBro2Name",
payload:e.target.value,
});
};
render(){
const { name:{ bro1, bro2 } } = this.props;
return(
<Fragment>
<h1>{bro1}</h1>
<Input value={bro2} onChange={this.handleChange}/>
</Fragment>
)
}
};
- 兄弟組件2
import { Component, Fragment } from "react";
import { Connect } from 'dva';
@connect(({ name })=>({
name,
}))
export default class Bro2 extends Component {
constructor() {
super();
};
handleChange = e => {
const { dispatch } = this.props;
dispatch({
type:"name/updateBro1Name",
payload:e.target.value,
});
};
render(){
const { name:{ bro1, bro2 } } = this.props;
return(
<Fragment>
<h1>{bro2}</h1>
<Input value={bro1} onChange={this.handleChange}/>
</Fragment>
)
}
};
- 共同的父組件
import { Component, Fragment } from "react";
import { Connect } from "dva";
@Connect(({ name })=>({
name,
}))
export default class Father extends Component {
render{
const { name:{ bro1, bro2 } } = this.props;
return (
<Fragment>
<Bro1/>
<Bro2/>
</Fragment>
)
}
};
- name.js 放置兩個兄弟組件的共同狀態
export default {
namespace: "name",
state : {
bro1: "",
bro2: "",
};
reducers: {
updateBro1Name(state,action){
return {
...state,
bro1 : action.payload,
}
};
updateBro2Name(state,action){
return {
...state,
bro2 : action.payload,
}
};
};
};
總結: 事實上是將一些共同的狀態存入一個更高的組件中存放着,從這個地方操作值和調用值。