react之使用Context跨组件树传递数据

react推崇的是单向数据流,自上而下进行数据的传递,但是由下而上或者不在一条数据流上的组件之间的通信就会变的复杂。解决通信问题的方法很多,如果只是父子级关系,父级可以将一个回调函数当作属性传递给子级,子级可以直接调用函数从而和父级通信。

组件层级嵌套到比较深,可以使用上下文getChildContext来传递信息,这样在不需要将函数一层层往下传,任何一层的子级都可以通过this.context直接访问。

兄弟关系的组件之间无法直接通信,它们只能利用同一层的上级作为中转站。而如果兄弟组件都是最高层的组件,为了能够让它们进行通信,必须在它们外层再套一层组件,这个外层的组件起着保存数据,传递信息的作用,这其实就是redux所做的事情。

组件之间的信息还可以通过全局事件来传递。不同页面可以通过参数传递数据,下个页面可以用location.param来获取。其实react本身很简单,难的在于如何优雅高效的实现组件之间数据的交流。

今天我们就来熟悉下react的context数据传递



没有使用Context的情况下传递数据, 我们可以参考React的文档:  Context , 它是通过组件属性一级一级往下传递. 这种方式很麻烦, 如果组件树比较深, 必须在每一个路径上的节点都引入不必要的属性.

定义 Context 的根组件


import React      from 'react';

# React 15.5版本以后, 使用PropTypes需要引入外部库, 直接使用React.PropTypes 会抛警告
import PropTypes from 'prop-types';

# React Router V4版本要从 react-router-dom 导入需要的组件
import { Route, Link } from 'react-router-dom';

import { Row, Col, Menu, Icon, Dropdown, Layout} from 'antd';
const { Sider, Content } = Layout;

import UserList   from './UserList';
import UserDetail from './UserDetail';
import Sidebar    from '../_layouts/Sidebar';

const avatars = [
  "elyse.png",
  "kristy.png",
  "matthew.png",
];

const data = [];
for(let i = 0; i <= avatars.length; i++){
  data.push({key: i, name: '胡彦祖3',age: 42,address: '西湖区湖底公园1号'});
}

const columns = [
  { title: 'ID',dataIndex: 'key',key: 'key'},
  { title: '姓名',dataIndex: 'name',key: 'name', render: function(text, record, index) {
    return (<Link to={`/users/${index}`}><div style={{display: 'block'}}>{text}</div></Link>)
  }},
  { title: '年龄',dataIndex: 'age',key: 'age'},
  { title: '住址',dataIndex: 'address',key: 'address'},
  {
    title: 'Action',
    key: 'action',
    render: function(text, record, index){
      return (
        <span>
          <a><Icon type="plus" /></a>
          <span className="ant-divider" />
          <a><Icon type="close" /></a>
        </span>
      )
    }
  }
];

class UserIndex extends React.Component {
  constructor(props){
    super(props)
  }

  # 定义Context需要实现的方法

  getChildContext() {
    return {
      data: data,
      columns: columns
    };
  }
  render(){
    return (
      <Layout>
        <Sider>
          <div id="user-side-bar" className="side-bar">
          <Sidebar/>
          </div>
        </Sider>
        <Content>
          <h2 className="pagetitle">用户信息页</h2>
          <Row gutter={16}>
            <Col span={16}>
              <UserList />
            </Col>
            <Col span={4}>
              <Route path={`${this.props.match.url}/:id`} component={UserDetail}/>
            </Col>
          </Row>
        </Content>
      </Layout>
    )
  }
}

# 声明Context类型

UserIndex.childContextTypes = {
  data: PropTypes.array,
  columns: PropTypes.array,
};

export default UserIndex;

中间组件


中间中间不再通过组件属性一级一级的往下传递了. 我们这里在 render() 函数中定义一个空的 <List/>:


import { Table, Icon } from 'antd';

import {
  Link
} from 'react-router-dom';

import List from '../_common/List';



class UserList extends React.Component {
  constructor(props){
    super(props)
  }
  render(){
    return (
      <div>
        <List />
      </div>
    )
  }
}

export default UserList;

子组件, 列表


import React from 'react';
import PropTypes from 'prop-types';
import { Layout, Table } from 'antd';
const { Sider, Content } = Layout;
class List extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Content>
        <Table columns={this.context.columns} dataSource={this.context.data} size="middle" />
      </Content>
    );
  }
}

List.propTypes = {
    data: PropTypes.array,
    columns: PropTypes.array
};

# 在这里声明 contextTypes 用于访问 UserIndex 组件中定义的Context数据.

List.contextTypes = {
  data: PropTypes.array,
  columns: PropTypes.array
};

export default List;


这样我们就可以在子组件中获取到父组件的数据了,不管多少层都能获取到。
React 中的 Context API 主要用于解决组件间的深度嵌套状态管理问题,特别是当子组件需要向远在形结构之外的父组件传递数据时。Context 提供了一种将共享数据向上“推”到组件的方式,而无需通过 prop 链一层层地往下传递。 **父组件获取子组件的数据流程:** 1. **创建 Context**: 创建一个名为 `MyContext` 的上下文对象,通常是一个自定义的 JavaScript 类或对象,包含你要共享的数据。 ```jsx const MyContext = React.createContext(); ``` 2. **提供数据**: 在父组件中作为 `Provider` 提供这个 Context 数据。 ```jsx import { Provider } from 'react-redux'; // 或者 import MyContext from './MyContext'; <Provider store={store} value={<MyContext.Provider value={{ data: 'from child' }} />} > {/* 子组件 */} </Provider> ``` 3. **使用数据**: 子组件通过 `<MyContext.Consumer>` 消费数据。 ```jsx <MyContext.Consumer> {(data) => ( <ChildComponent data={data.data} /> {/* 子组件可以接收到并使用数据 */} )} </MyContext.Consumer> ``` 4. **子组件传递数据给父组件**: 如果有特殊情况,子组件想直接将数据传递给父组件,它可以直接通过 prop 将数据返回,但是这种方式并不推荐,因为违背了 Context 的初衷。 **相关问题--:** 1. 如何避免在大型项目中过度使用 Context? 2. React Context 和 Redux 这两种状态管理方案有何区别? 3. 当组件不再需要从 Context 中接收数据时,应该如何处理?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值