组件通信
复合组件:父组件嵌套子组件
方案一:属性传递(适用于父与子)
调取子组件的时候,把信息基于属性的方式传递给子组件(子组件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.父组件设置childContextTypes
和getChildContext
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.Provider
和ThemeContext.Consumer
标签进行信息传递
属性传递 VS 上下文传递
1.接收值的方式:属性传递时子组件通过props
被动接收传递的值,而上下文传递时子组件是主动通过contextTypes
挑选自己需要的值
2.值的可修改性:属性传递中父传子的属性属于只读属性,不可修改,最多只能通过defaultProps
设置未传时的默认值,而上下文传递时子组件是可以修改获取到的上下文信息的(但是不会影响到父组件中的信息,其它组件不受影响)
3.后代接收方式:属性传递只能一层层地进行传递,即若想实现父传孙,则必须先父传子,再进行子传孙才可实现,而上下文传递时后代组件可以直接使用父组件设置好的上下文信息,不需要一层层进行传递
4.操作难易程度:属性传递操作起来相对方便简单,而上下文传递操作起来相对繁琐一些
平行组件:兄弟组件或者毫无关系的两个组件
方案一:让两个平行组件拥一个共同的父组件
父组件中有一些信息,父组件把一个方法传递给A,A中把方法执行(方法执行修改父组件信息值),父组件再把最新的信息传递给B即可,等价于A操作,影响了B
方案二:Redux
进行状态统一管理的类库(适用于任何技术体系的项目)
- 基本流程
1.createStore(reducer)
创建redux公共状态管理器
2.设置管理员函数import {createStore} from 'redux'; let store = createStore(reducer);
reducer(state,action)
3.子组件由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返回,原有的状态才会被修改 };
store.getState()
获取公共状态信息,父子的通信可以用组件通信的方案实现
4.let {store: {getState}} = this.props, {n, m} = getState(); this.state = {n, m};
store.dispatch()
派发行为通知reducer修改状态
5.子组件通过<button className={'btn btn-success'} onClick={() => { dispatch({ type: 'VOTE_SUPPORT' }); }}>支持</button> <button className={'btn btn-danger'} onClick={() => { dispatch({ type: 'VOTE_AGAINST' }); }}>反对</button>
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挂载到祖先元素的上下文中,供内部任何后代组件使用
3.在子组件中通过render(<Provider store={store}> <section className='panel panel-default'> <VoteBase/> <VoteHandle/> </section> </Provider>, root);
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这种格式
网友评论