美文网首页
React入门(四)

React入门(四)

作者: Leonard被注册了 | 来源:发表于2019-12-12 09:52 被阅读0次

    组件通信


    复合组件:父组件嵌套子组件

    方案一:属性传递(适用于父与子)

           调取子组件的时候,把信息基于属性的方式传递给子组件(子组件props中存储传递的信息),这种方式只能是父组件把信息传递子组件,子组件无法直接地把信息传递给父组件,也就是说属性传递信息是单向传递的。不过利用回调函数机制也可以实现子改父的效果,即父组件把一个函数通过属性或者上下文的方式传递给子组件,子组件中只要把这个方法执行即可

    /*HEAD*/
    class Head extends React.Component {
        render() {
            return <div className='panel-heading'>
                <h3 className='panel-title'>
                    {/*子组件通过属性获取父组件传递的状态*/}
                    点击次数:{this.props.count}
                </h3>
            </div>;
        }
    }
    
    /*BODY*/
    class Body extends React.Component {
        render() {
            return <div className='panel-body'>
                <button className='btn btn-success'
                        {/*子组件通过属性获取父组件传递的方法*/}
                        onClick={this.props.callBack}>点我啊!
                </button>
            </div>;
        }
    }
    
    /*PANEL*/
    class Panel extends React.Component {
        constructor() {
            super();
            this.state = {n: 0};
        }
    
        fn = () => {
            // 修改PANEL的状态信息
            this.setState({
                n: this.state.n + 1
            });
        };
    
        render() {
            return <section className='panel panel-default' style={{width: '50%', margin: '20px auto'}}>
                {/*父组件中在调取子组件的时候,把信息通过属性传递给子组件*/}
                <Head count={this.state.n}/>
    
                {/*父组件把自己的一个方法基于属性传递给子组件,目的是在子组件中执行这个方法*/}
                <Body callBack={this.fn}/>
            </section>;
        }
    }
    
    效果演示

    方案二:发布订阅方式

    1.调用父组件创建一个属于自己的事件池
    2.在子组件中把修改本身状态的方法放到事件池中
    3.在点击按钮的时候,通知事件池中的方法执行即可

    方案三:基于上下文进行传递

           父组件先把需要给后代元素(包括孙子元素)使用的信息都设置好(设置在上下文中),后代组件需要用到父组件中的信息,主动去父组件中调取使用即可

    • 方法一
      1.父组件设置childContextTypesgetChildContext
      2.子组件通过contextTypes获取上下文
      // 父组件设置信息
      static childContextTypes = {
          // 设置上下文中信息值的类型,需借助prop-types
          n: PropTypes.number,
          m: PropTypes.number
      };
      getChildContext() {
          // RETURN的是啥,相当相当于往上下文中放了啥
          let {count: {n = 0, m = 0}} = this.props;
          return {
              n,
              m
          };
      }
      
      // 子组件主动获取需要的信息
      static contextTypes = {
          // 首先类型需要和设置时类型一致,否则报错;然后根据需求提取上下文的内容即可
          n: PropTypes.number,
          m: PropTypes.number
      };
      
    • 方法二
      1.React.createContext()创建上下文
      2.通过ThemeContext.ProviderThemeContext.Consumer标签进行信息传递

    属性传递 VS 上下文传递

    1.接收值的方式:属性传递时子组件通过props被动接收传递的值,而上下文传递时子组件是主动通过contextTypes挑选自己需要的值
    2.值的可修改性:属性传递中父传子的属性属于只读属性,不可修改,最多只能通过defaultProps设置未传时的默认值,而上下文传递时子组件是可以修改获取到的上下文信息的(但是不会影响到父组件中的信息,其它组件不受影响)
    3.后代接收方式:属性传递只能一层层地进行传递,即若想实现父传孙,则必须先父传子,再进行子传孙才可实现,而上下文传递时后代组件可以直接使用父组件设置好的上下文信息,不需要一层层进行传递
    4.操作难易程度:属性传递操作起来相对方便简单,而上下文传递操作起来相对繁琐一些


    平行组件:兄弟组件或者毫无关系的两个组件

    方案一:让两个平行组件拥一个共同的父组件

           父组件中有一些信息,父组件把一个方法传递给A,A中把方法执行(方法执行修改父组件信息值),父组件再把最新的信息传递给B即可,等价于A操作,影响了B

    方案二:Redux

    进行状态统一管理的类库(适用于任何技术体系的项目)

    • 基本流程
      1.createStore(reducer)创建redux公共状态管理器
      import {createStore} from 'redux';
      let store = createStore(reducer);
      
      2.设置管理员函数reducer(state,action)
      let reducer = (state = {n: 0, m: 0}, action) => {
          switch (action.type) {
              case 'VOTE_SUPPORT':
                  state = {...state, n: state.n + 1};
                  break;
              case 'VOTE_AGAINST':
                  state = {...state, m: state.m + 1};
                  break;
          }
          return state;// 只有把最新的STATE返回,原有的状态才会被修改
      };
      
      3.子组件由store.getState()获取公共状态信息,父子的通信可以用组件通信的方案实现
      let {store: {getState}} = this.props,
          {n, m} = getState();
      this.state = {n, m};
      
      4.store.dispatch()派发行为通知reducer修改状态
      <button className={'btn btn-success'} onClick={() => {
             dispatch({
                type: 'VOTE_SUPPORT'
             });
      }}>支持</button>
      <button className={'btn btn-danger'} onClick={() => {
             dispatch({
                 type: 'VOTE_AGAINST'
             });
      }}>反对</button>
      
      5.子组件通过store.subscribe()把方法追加到事件池中让其进行组件的重新渲染
      componentDidMount() {
            this.props.store.subscribe(() => {
                this.forceUpdate();
            });
        }
      
    • 工程化管理目录结构
      |-store
        |- index.js 创建redux容器
        |- action-type.js 宏管理行为派发标识
        |- reducers
          |- index.js 各板块合并后的reducer
          |- xxxReducer.js
        |- actions
          |- index.js 各板块合并后的action
          |- xxxAction.js
    • REACT-REDUX(把REDUX进一步封装,适配REACT项目,让REDUX操作更简洁)
      React提供了自己的一套redux管理体系,其基本流程如下:
      1.工程化管理目录与redux一致
      2.利用Provider把创建的store挂载到祖先元素的上下文中,供内部任何后代组件使用
      render(<Provider store={store}>
          <section className='panel panel-default'>
              <VoteBase/>
              <VoteHandle/>
          </section>
      </Provider>, root);
      
      3.在子组件中通过connect高阶组件实现获取公共状态、重新渲染、行为派发等一系列流程
      import {connect} from 'react-redux';
      // 把REDUX容器中的状态信息遍历,赋值给当前组件的属性(state)
      let mapStateToProps = state => {
          // state:就是REDUX容器中的状态信息
          // return的是啥,就把它挂载到当前组件的属性上(REDUX存储很多信息,想用啥就返回啥即可)
          return {
              ...state.vote
          };
      };
      
      // 把REDUX中的DISPATCH派发行为遍历,也赋值给组件的属性(ActionCreator)
      let mapDispatchToProps = dispatch => {
          // dispatch:STORE中存储的DISPATCH方法
          // 返回的是啥,就相当于把啥挂载到组件的属性上(一般会挂载一些方法,这些方法中完成了DISPATCH派发任务操作)
          return {
              init(initData) {
                  dispatch(action.vote.init(initData));
              }
          };
      };
      export default connect(mapStateToProps, mapDispatchToProps)(VoteBase);
      
      // 简化写法
      export default connect(state => ({...state.vote}), action.vote)(VoteBase);     // REACT-REDUX帮我们做了一件事情,把ACTION-CREATOR中编写的方法(返回ACTION对象的方法),自动构建成DISPATCH派发任务的方法,也就是mapDispatchToProps这种格式
      

    相关文章

      网友评论

          本文标题:React入门(四)

          本文链接:https://www.haomeiwen.com/subject/yxzngctx.html