父组件传递子组件
传递元素内容
如果给自定义组件传递元素内容,则React会将元素内容作为children属性传递过去
todo…
子组件是 class 组件
-
第一种方式:直接在 constructor 中使用 this.props = props 的方式通信;
import React, { Component } from 'react'; // 1.类子组件 class ChildCpn1 extends Component { constructor(props) { super(); this.props = props; } render() { const { name, age, height } = this.props; return ( <div> <h2>我是class的组件</h2> <p>展示父组件传递过来的数据: {name + " " + age + " " + height}</p> </div> ) } } export default class App extends Component { render() { return ( <div> <ChildCpn1 name="why" age="18" height="1.88" /> </div> ) } }
-
第二种方式:可以调用 super(props) 的方式通信;
- 先看一下 Component 的源码,就知道为什么可以这样通信了
function Component(props, context, updater) { this.props = props; this.context = context; // If a component has string refs, we will assign a different object later. this.refs = emptyObject; // We initialize the default updater but the real one gets injected by the // renderer. this.updater = updater || ReactNoopUpdateQueue; }
- 所以可以书写成这样:
constructor(props) { super(props); }
-
第三种方式:省略构造函数,如果不指定构造方法,则使用默认构造函数:
- 对于基类,默认构造函数是:
constructor() {}
- 对于派生类,默认构造函数是:
constructor(...args) { super(...args); }
子组件是 function 组件
-
子组件是 function 组件,直接解构 props 即可:
function ChildCpn2(props) { const { name, age, height } = props; return ( <div> <h2>我是function的组件</h2> <p>展示父组件传递过来的数据: {name + " " + age + " " + height}</p> </div> ); } export default class App extends Component { render() { return ( <div> <ChildCpn2 name="kobe" age="30" height="1.98" /> </div> ); } }
-
functional 组件 相对来说比较简单,因为不需要有构造方法,也不需要有 this 的问题;
子组件传递父组件
-
某些情况,子组件也需要向父组件传递消息:
- 在 vue 中是通过自定义事件来完成的;
- 在 React 中同样是通过 props 传递消息,只是让父组件给子组件传递一个回调函数,在子组件中调用这个函数即可;
-
计数器案例:
import React, { Component } from 'react'; // 子组件 function CounterButton(props) { const { operator, btnClick } = props; // 将按钮封装到子组件中,发生点击事件,将内容传递到父组件中 return <button onClick={btnClick}>{operator}</button> } export default class App extends Component { constructor(props) { super(props); this.state = { counter: 0 } } changeCounter(count) { this.setState({ counter: this.state.counter + count }) } render() { return ( <div> <h2>当前计数: {this.state.counter}</h2> <CounterButton operator="+1" btnClick={e => this.changeCounter(1)} /> <CounterButton operator="-1" btnClick={e => this.changeCounter(-1)} /> </div> ) } }
组件通信案例
// index.js
import React from "react";
import ReactDOM from "react-dom";
import "./style.css";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
// App.js
import React, { Component } from "react";
import TabControl from "./TabControl";
export default class App extends Component {
constructor(props) {
super(props);
this.titles = ["流行", "新款", "精选"];
this.state = {
currentTitle: "流行",
};
}
itemClick(index) {
this.setState({
currentTitle: this.titles[index],
});
}
render() {
return (
<div>
<TabControl titles={this.titles} clickTitle={(index) => this.itemClick(index)} />
<h2>{this.state.currentTitle}</h2>
</div>
);
}
}
// TabControl.js
import React, { Component } from "react";
export default class TabControl extends Component {
constructor(props) {
super(props);
this.state = {
currentIndex: 0,
};
}
render() {
const { titles } = this.props;
const { currentIndex } = this.state;
return (
<div className="tab-control">
{titles.map((item, index) => {
return (
<div className="tab-item" onClick={(e) => this.itemClick(index)}>
<span
className={"title " + (index === currentIndex ? "active" : "")}
>
{item}
</span>
</div>
);
})}
</div>
);
}
itemClick(index) {
this.setState({
currentIndex: index,
});
this.props.clickTitle(index);
}
}
.tab-control {
height: 40px;
line-height: 40px;
display: flex;
}
.tab-control .tab-item {
flex: 1;
text-align: center;
}
.tab-control .title {
padding: 3px 5px;
}
.tab-control .title.active {
color: red;
border-bottom: 3px solid red;
}
React 插槽
Vue 插槽固定的做法是通过 slot 来完成;
React 插槽有 children、props 两种方案可以实现,非常灵活;
children 实现
-
每个组件都可以获取到 props.children,它包含组件的开始标签和结束标签之间的内容;
-
props.children 的源码实现:
- 如果只有一个元素,那么 children 指向该元素;
- 如果有多个元素,那么 children 指向的是数组,数组中包含多个元素;
-
示例代码:
import React, { Component } from 'react'; class NavBar extends Component { render() { return ( <div className="nav-bar"> <div className="item left">{this.props.children[0]}</div> <div className="item center">{this.props.children[1]}</div> <div className="item right">{this.props.children[2]}</div> </div> ) } } export default class App extends Component { render() { return ( <div> <NavBar> <div>返回</div> <div>购物街</div> <div>更多</div> </NavBar> </div> ) } }
props 实现 (推荐)
-
通过 children 实现的方案虽然可行,但是有一个弊端:通过索引值获取传入的元素很容易出错,不能精准的获取传入的原生;
-
另外一个种方案就是使用 props 实现,通过具体的属性名,可以在传入和获取时更加的精准;
import React, { Component } from 'react'; class NavBar extends Component { render() { const { leftSlot, centerSlot, rightSlot } = this.props; return ( <div className="nav-bar"> <div className="item left">{leftSlot}</div> <div className="item center">{centerSlot}</div> <div className="item right">{rightSlot}</div> </div> ) } } export default class App extends Component { render() { const navLeft = <div>返回</div>; const navCenter = <div>购物街</div>; const navRight = <div>更多</div>; return ( <div> <NavBar leftSlot={navLeft} centerSlot={navCenter} rightSlot={navRight} /> </div> ) } }
Pinia 添加插件
上一篇