属性传递:调取子组件的时候,把信息基于属性的方式传递给子组件(子组件props中存储传递的信息),这种方式只能父组件把信息传递给子组件,子组件无法直接的把信息传递给父组件,也就是属性传递信息是单向传递的;
export default class Vote extends React.Component { static defaultProps = { title: '标题不知道,随便投', }; constructor(props) { super(props); } render() { let {title} = this.props; return <VoteHead title={title}/>双下文传递:父组件先把需要给后代元素(包括孙子元素)使用的信息都设置好(设置在上下文中),后代组件需要用到父组件中的信息,主动去父组件中调用使用即可
/* 在父组件中 设置子组件上下文属性类型 static childContextTypes={} 获取子组件的上下文(设置子组件的上下文属性信息) getChildContext(){} */ static childContextTypes = { //设置上下文信息值的类型 n: PropTypes.number, m: PropTypes.number, }; getChildContext() { //return 是啥就是想当于给子组件设置下上文 let {count: {n = 0, m = 0}} = this.props; return { n, m, } } /* * 子组件设置使用传递进来的上下文类型 * 设置那个的类型,子组件上下文中才有那个属性,不设置是不允许使用的 * this.context.xxx * 指定的上下文属性类型需要和父组件指定的类型保持一致,否则报错 * */ static contextTypes={ n:PropTypes.number, m:PropTypes.number }; constructor(props,context){ super(props,context); this.context.n=1000 }属性VS 上下文
属性操作起来简单,子组件是被动接受传递的值(组件内的属性是只读的),只能父传子(子传父不行,父传孙也需要处理:子传子,子再传孙)
上下文操作起来相对复杂一些,子组件是主动获取信息使用的(子组件是可以修改获取的上下文信息,但是不会影响到父组件中的信息,其他组件不受影响),一旦父组件设置了上下文信息,他后代组件都可以直接拿到,不需要不层层的传递
其实子组件也能修改父组件中的信息
利用回调函数机制: 父组件把一个函数通过属性或者上下文的方式传递给子组件,子组件要把这个方法执行即可
(也就是子组件中执行了父组件方法,还可以传递一些值过去),这样组件在这个方法中,想把自己的信息改成啥就改成啥
/* 在父组件中 设置子组件上下文属性类型 static childContextTypes={} 获取子组件的上下文(设置子组件的上下文属性信息) getChildContext(){} */ static childContextTypes = { n: PropTypes.number, m: PropTypes.number, callBack: PropTypes.func }; getChildContext() { //return 是啥就是想当于给子组件设置下上文 //只要render重新渲染,就会执行这个方法,重新更新父组件中的上下文信息,如果父组件上下文 //信息更改了,子组件在重新调取的时候,会使用最新的上下文信息(render=>context=>子组件调取渲染) let {n, m} = this.state; return { n, m, callBack: this.updateContext } } updateContext = type => { //type :'support'http://www.likecs.com/'against' if (type === 'support') { this.setState({n: this.state.n + 1}); return; } return this.setState({m:this.state.m-1}) }; //子组件 <button className={'btn btn-danger'} onClick={ ()=>{ callBack('against'); } }>反对</button>平行组件:兄弟组件或者毫无关系的两个组件
让两个平行组件拥有一个共同的父组件
基于redux来进行状态管理,实现组件之间的信息传递
redux可以应用在任何项目中(vue/jq/react的都可以),react-redux才是专门给react项目提供的方案
yarn add redux react-redux //index.js //创建一个容器: 需要把reducer 传递进来(登记了所有状态更改的信息) import {createStore} from 'redux'; /*reducer 作用: 1. 记录了所有状态修改的信息(根据行为标识走不同的修改任务) 2. 修改容器中的状态信息 [参数] state:容器中原有的状态信息(如果第一次使用,没有原有状态,给一个厨师默认值 action: dispatch 任务派发的时候传递的行为对象(这个对象中必有一个type属性,是操作的行为标识, reducer 就是根据这个行为标识来识别修改状态信息 * */ let reducer = (state = {n: 0, m: 0}, action) => { switch (action.type) { case 'VOTE_SUPPORT': //vote_support state = {...state, n: state.n + 1}; break; case 'VOTE_AGAINST': //vote_against state = {...state, m: state.m + 1}; break; } return state;// 只有把最新的state返回,原有的状态才会修改 }; let store = createStore(reducer); /* * 创建store 提供三个方法: * dispatch: 派发行为(传递一个对象,对象中有一个type属性,通知reducer修改状态信息 * subscribe: 事件池追加方法 * getState: 获取最新管理的状态信息 * */ <Vote title={'英格兰对战巴拿马,合力必胜'} count={{ n: 100, m: 78 }} store={store}/> //Vote.js import React from 'react'; import PropTypes from 'prop-types'; import VoteHead from './VoteHead'; import VoteBody from './VoteBody'; import VoteFooter from "./VoteFooter"; export default class Vote extends React.Component { static defaultProps = { title: '', count: { n: 0, m: 0, } }; constructor(props) { super(props); }; render() { let {store} = this.props; return <section className={'panel-heading'} style={{width: '50%', height: '20px auto'}}> <VoteHead title={this.props.title}/> <VoteBody store={store}/> <VoteFooter store={store}/> </section> } } //VoteBody.js import React from 'react'; import PropTypes from 'prop-types'; export default class VoteBody extends React.Component { constructor(props) { super(props); //init state let {store: {getState}} = this.props, {n, m} = getState(); this.state = {n, m}; } componentDidMount() { let {store: {getState, subscribe}} = this.props; let unsubscribe = subscribe(() => { let {n, m} = getState(); this.setState({ n, m }) }); //unsubscribe(): 当前追加的方法移出,接触绑定的方式 } render() { let {n, m} = this.state, rate = (n / (n + m)) * 100; if (isNaN(rate)) { rate = 0; } return <div className={'panel-body'}> 支持人数: <span>{n}</span> <br/> 反对人数: <span>{m}</span> <br/> 支持比率: <span>{rate.toFixed(2) + '%'}</span> </div>; } } //VoteFooter.js import React from 'react'; import PropTypes from 'prop-types'; export default class VoteFooter extends React.Component { constructor(props, context) { super(props, context); } render() { let {store: {dispatch}} = this.props; return <div className={'panel-footer'}> <button className={'btn btn-success'} onClick={() => { dispatch({ type: 'VOTE_SUPPORT' }) }} >支持 </button> <button className={'btn btn-danger'} onClick={ () => { dispatch({ type: 'VOTE_AGAINST' }) } }>反对 </button> </div> } } Reduxredux:进行状态统一管理的类库(适用于任何技术体系的项目)
只要两个或者多个组件之间想要实现信息的共享,都可以基于redux解决,把共享的信息到redux容器中进行管理