子传父——函数传递
- 在 vue 中是通过自定义事件来完成的
- 在 react 中同样是通过 props 来传递信息,只不过这个 props 是一个回调函数。父组件在引入的子组件中传递一个函数,并传参,子组件去触发这个函数更改参数完成数据更新
- 注意,父组件向子组件传值时,要用
increment = {e => this.increment()}的方式传递一个箭头函数过去,这样就没有 this 绑定的问题了。
案例:tabControl组件的实现
- 要实现的功能如下,点击后进行切换:

首先我们写一个最外层组件
class App extends React.Component {constructor(props) {super(props);this.titles = ['路飞','索隆','艾斯'];this.state = {currentTitle: '路飞',titles: ['路飞','索隆','艾斯']}}render() {return (<div><TabControl itemClick={index => this.itemClick(index)} titles={this.titles} /><h2>{ currentTitle }</h2></div>)}itemClick(index) {this.setState({currentTitle: this.titles[index]})}}
再写一个子组件
class TabControl extends React.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 (<divkey={index}className={"tab-item" + (index === currentIndex ? "active" : "")}onClick={e => this.itemClick(index)}><span>{item}</span></div>)})}</div>)itemClick(index) {this.setState({currentIndex: index})const {itemClick} = this.propsitemClick(index)}}}
React中实现类似vue的slot(插槽)功能
- ….
跨组件通信——props
// 头部组件function ProfileHeader(props) {return (<div><h2>用户昵称:{props.nickName}</h2><h2>用户等级:{props.level}</h2></div>)}// 列表组件function Profile(props) {return (<div><ProfileHeader nickName={props.nickName} level={props.level}/><ul><li>list1</li><li>list2</li><li>list3</li><li>list4</li></ul></div>)}// 最外层组件class App extends React.Component {constructor(props) {super(props);this.state = {nickName: "ryan",level: "99"}}render() {const {nickName, level} = this.state;return (<div><Profile nickName={nickName} level={level} /></div>)}}ReactDOM.render(<App/>, document.getElementById("App"));
- 展示如下:

如上这种写法是很麻烦的,而且中间层 Profile 都没有用到那两个参数,但是为了传给子组件,必须接受下,所以这种跨组件的通信我们是不用的。有一种语法
,效果和如上一样
跨组件通信——context
- 非父子组件间数据的共享:
- 开发中,比较常见的数据传递方式是通过
props属性自上而下(父到子)进行传递 - 但是对于一些场景:一个数据要在多个组件中进行共享(地区偏好、UI主题、用户登录状态,用户信息等)
- 如果我们再顶层的
App中定义了这些信息,之后一层层传递下去,那么对于一些不需要这些数据的中间层来说,是一种冗余的操作 - 而且,如果层级更多,一层层传递非常麻烦,所以我们使用一种别的办法来实现
- 开发中,比较常见的数据传递方式是通过
- React 提供了一个API
contextcontext提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递propscontext设计的目的是为了共享那些对于一个组件树而言是“全局”的数据,如当前认证的用户,主题,或者首选语言
context相关API- React.createContext
- 创建一个需要共享的
Context对象 - 如果一个组件订阅了
Context,那么这个组件会从离自身最近的那个匹配的Provider中读取到当前的Context值 defaultValue是组件在顶层查找过程中没有找到对应的Provider,那么就是用的默认值const MyContext = React.createContext(defaultValue);
- 创建一个需要共享的
- Context.Provider
- 每个
Context对象都返回一个Provider React组件,它允许消费组件订阅Context的变化 Provider接收一个 value 属性,传递给消费组件- 一个
Provider可以和多个消费组件有对应关系 - 多个
Provider也可以嵌套使用,里层的会覆盖外层的数据 - 当
Provider的 value 值发生变化时,它内部的所有消费组件都会重新渲染
- 每个
- Class.contextType
- 挂载在 class 上的
contextType属性会被重新赋值未一个由React.createContext()创建的Context对象 - 这能让你使用
this.context来消费最近Context上的那个值 - 你可以在任何生命周期中访问到它,包括 render 函数中
Myclass.contextType = MyContext;
- 挂载在 class 上的
- Context.Consumer
- 这里,React 组件也可以订阅到
Context变化,这能让你在函数式组件中完成订阅Context - 这里需要函数作为子元素(function as child)这种做法
- 这个函数接收当前的
Context值,返回一个 React 节点
- 这里,React 组件也可以订阅到
- React.createContext
- 基本使用 ```javascript
// 1. 创建一个context对象 const UserContext = React.createContext({ nickName: ‘ryan’, level: 100 });
// 头部组件 function ProfileHeader(props) { return (
用户昵称:{props.nickName}
用户等级:{props.level}
// 列表组件 function Profile(props) { return (
- list1
- list2
- list3
- list4
// 最外层组件 class App extends React.Component { constructor(props) { super(props);
this.state = {nickName: "ryan",level: "99"}
}
render() { return (
// 2. 因为ProfileHeader要共享数据,在App组件中使用.provider内置组建,必须要共享数据的组建
// 是被共享组件的子孙组件
)
}
}
ReactDOM.render(
