React 组件
- 组件是元素复用的思想,也是组件化框架的最主要的特征。我们现在要把网页的菜单栏看出一个组件,然后独立的抽象出来,这样做之后,任何需要菜单的页面只要导入该组件,就可以实现代码复用,让维护和扩展都变得简单。
组件有两个核心概念:
props
props 就是组件的属性,由外部通过 JSX 属性传入设置,一旦初始设置完成,就可以认为 this.props 是不可更改的,所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。
state
state 是组件的当前状态,可以把组件简单看成一个“状态机”,根据状态 state 呈现不同的 UI 展示。 一旦状态(数据)更改,组件就会自动调用 render 重新渲染 UI,这个更改的动作会通过 this.setState 方法来触发。setState是React事件处理函数中和请求回调函数中触发UI更新的主要方法。
复合组件
- 创建多个组件来合成一个组件,即把组件的不同功能点进行分离
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 实例</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
function Name(props) {
return <h1>网站名称:{props.name}</h1>;
}
function Url(props) {
return <h1>网站地址:{props.url}</h1>;
}
function Nickname(props) {
return <h1>网站小名:{props.nickname}</h1>;
}
function App() {
return (
<div>
<Name name="百度一下" />
<Url url="http://www.baidu.com" />
<Nickname nickname="百度" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('example')
);
</script>
</body>
</html>
React -- 组件间通信
分为三种类型的通信关系:
1、父组件向子组件通信
2、子组件向父组件通信
3、没有嵌套关系的组件之间的通信
父组件向子组件通信
父组件通过子组件的props向子组件传递需要的信息。
子组件向父组件通信
两种方法:
1、利用回调函数
2、利用自定义事件机制
ListItem.js:
import React, { Component } from 'react';
class ListItem extends Component{
static defaultProps = {
text: '',
checked: false,
}
render() {
return(
<li>
<input type="checkbox" checked={this.props.checked} onChange={this.props.onChange}/>
<span>{this.props.value}</span>
</li>
)
}
}
export default ListItem
List.js:
import React, { Component } from 'react';
import ListItem from './ListItem';
class List extends Component {
constructor(props) {
super(props);
this.state = {
list: [
{
text: '苹果',
checked: false
},
{
text: '草莓',
checked: false
}
]
}
}
onItemChange(val) {
const {list} = this.state
this.setState({
list: list.map((item) =>({
text: item.text,
checked: item.text == val.text ? !item.checked: item.checked
}))
})
}
render() {
return (
<div>
{
this.state.list.map((item, index) =>{
return (
<ListItem
key={index}
checked={item.checked}
value={item.text}
onChange={this.onItemChange.bind(this, item)}
/>
)
})
}
</div>
)
}
}
export default List;
App.js:
import React, { Component } from 'react';
import List from './List'
class APP extends Component {
render() {
return (
<List />
)
}
}
export default APP;
跨级组件通信 context来实现跨级通信。
Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递.
List.js:
import React from 'react';
import ListItem from './ListItem';
import MyContext from './context';
class List extends React.Component {
constructor(props) {
super(props)
this.state = {
msg: ''
}
}
fromGranson(val){
this.setState({msg: val})
}
// 使用一个 Provider 来将当前的 value 传递给以下的组件树。
// 无论多深,任何组件都能读取这个值。
render(){
return (
<div style={{backgroundColor:'#f7ba2a',padding:'20px',width:'500px',margin:'auto',textAlign:'center'}}>
<p>context通信实例第一层</p>
<span style={{color: 'red',fontSize:'30px'}}>{this.state.msg}</span>
<MyContext.Provider value={{text: '今天星期五',toParent: this.fromGranson.bind(this)}}>
<Son1/>
</MyContext.Provider>
</div>
)
}
}
// 导出组件
export default List;
ListItem.js:
import React from 'react';
import Grandson from './Grandson';
class ListItem extends React.Component {
render(){
return (
<div>
<Grandson></Grandson>
</div>
)
}
}
// 导出组件
export default ListItem;
Grandson.js:
import React from 'react';
import MyContext from './context';
class Grandson extends React.Component {
// 指定 contextType 读取当前的 MyContext
/*
挂载在 class 上的 contextType 属性可以赋值为由 React.createContext() 创建的 Context 对象。
此属性可以让你使用 this.context 来获取最近 Context 上的值。
你可以在任何生命周期中访问到它,包括 render 函数中。
*/
static contextType = MyContext
constructor(props) {
super(props)
}
toParent()
{
this.context.toParent('孙组件向爷爷组件传数据')
}
render() {
return(
<div style={{backgroundColor:'#13ce66',padding:'10px',width:'200px',margin:'auto',marginTop:'20px'}}>
<p>通过context传过来:</p>
<span style={{color:'blue'}}>{this.context.text}第四层</span>
<button onClick={() => this.toParent()}>context向上</button>
</div>
)
}
}
export default Grandson
context.js:
import React from "react";
const MyContext = React.createContext({text:'我是一个文本'});
export default MyContext
App.js:
import React, { Component } from 'react';
import List from './List'
class APP extends Component {
render() {
return (
<List />
)
}
}
export default APP;
没有嵌套关系的组件通讯
events.js:
// events.js(以常用的发布/订阅模式举例,借用Node.js Events模块的浏览器版实现)
import { EventEmitter } from 'events';
export default new EventEmitter();
OneList.js:
import React, { Component } from 'react';
import emitter from './events';
class OneList extends Component {
constructor(props) {
super(props);
this.state = {
message: 'oneList',
};
}
componentDidMount() {
// 组件装载完成以后声明一个自定义事件,也就是订阅事件
this.eventEmitter = emitter.addListener('changeMessage', (message) => {
this.setState({
message,
});
});
}
componentWillUnmount() {
// 取消订阅,就是销毁事件
emitter.removeAllListeners(this.eventEmitter);
}
render() {
return (
<div>
{this.state.message}
</div>
);
}
}
export default OneList;
TwoList.js:
import React, { Component } from 'react';
import emitter from './events';
class TwoList extends Component {
handleClick = (message) => {
// 发布事件,也就是触发事件
emitter.emit('changeMessage', message);
};
render() {
return (
<div>
<button onClick={this.handleClick.bind(this, 'TwoList')}>点击我改变OneList组件中显示信息</button>
</div>
);
}
}
export default TwoList;
App.js:
import React, { Component } from 'react';
import OneList from './OneList'
import TwoList from './TwoList'
class APP extends Component {
render() {
return (
<OneList/>
<TwoList/>
)
}
}
export default APP;