Hello React
是什么?
React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作“组件”。
为什么?
ps: 公司用
怎么用?
创建项目
// 创建项目
npx create-react-app my-app
// 进入项目目录,运行项目
npm start
Props(属性)
大多数组件在创建时就可以使用各种参数来进行定制。用于定制的这些参数就称为 props(属性)
- 标签中使用 {} 拿数据
- 脚本中使用 this.props.xx 拿数据
State(状态)
React中使用两种数据来控制一个组件: props 和 state。 props 是在父组件中指定,而且一经指定, 在被指定的组件的生命周期中则不在改变。对于需要改变的数据,需要使用 state
- 一切界面变化都是 状态state变化
- state 的修改必须通过 setState() 方法
- this.state.likes = 100; // 直接赋值修改无效
- setState 是一个 merge 合并操作, 只修改指定属性, 不影响其他属性
- setState 是异步操作, 修改不会马上生效
- 每次调用 setState 时,BlinkApp都会重新执行 render 方法重新渲染。
React 组件通信的几种方式
父组件向子组件通信
父组件引入子组件时,在子组件标签上传入对应的值(props),由子组件接收(props)。
childComponent.js
import React from "react";
const Child= (props) => {
return(
<h1>
{ props.title }
</h1>
)
}
export default Sub;
app.js
import React from 'react';
import Child from './ChildComponent';
function App() {
return (
<div className="App">
<Child title="Hello World!"/>
</div>
);
}
export default App;
子组件向父组件通信
利用回调函数,可以实现子组件向父组件通信: 父组件将一个函数作为 props 传递给子组件,子组件调用该回调函数,便可以向父组件通信。
childComponent.js
import React from "react";
const Child = (props) => {
const clickButton = (msg) => {
return () => {
props.callback(msg)
}
}
return(
<div>
<h1>
{ props.title }
</h1>
<button onClick = { clickButton('我是控制台打印的信息呀!' )} >click button</button>
</div>
)
}
export default Child;
app.js
import React,{ Component } from "react";
import Child from './ChildComponent';
export default class App extends Component{
callback(msg){
console.log(msg);
}
render(){
return(
<div className="App">
<Child title="Hello World!" callback = { this.callback.bind(this) }/>
</div>
)
}
}
跨级组件通信
父组件向子组件的子组件通信,向更深层的子组件通信
有两种方式:
- 中间组件层层传递 props : 增加复杂度,三层以上最好不用
- 使用 context 对象 : 相当于一个全局变量,是一个大容器
使用 context 需要满足两个条件:
- 上级组件要声明自己支持 context, 并提供一个函数来返回相应的 context 对象
- 子组件要申明自己需要使用 context
childChildComponent.js
import React,{ Component } from "react";
import PropTypes from "prop-types";
export default class ChildChild extends Component{
// 子组件声明自己需要使用 context
static contextTypes = {
color: PropTypes.string,
callback: PropTypes.func,
}
render(){
const style = { color: this.context.color }
const clickButtion = (msg) => {
return () => {
this.context.callback(msg);
}
}
return(
<div style = { style }>
ChildChild<br/>
<button onClick = { clickButtion("孩子的孩子") }>child button2</button>
</div>
);
}
}
childComponent.js
import React from "react";
import ChildChild from './ChildChildComponent'
const Child = (props) => {
const clickButton = (msg) => {
return () => {
props.callback(msg)
}
}
return(
<div>
<h1>
{ props.title }
</h1>
<button onClick = { clickButton('我是控制台打印的信息呀!' )} >click button</button>
<hr/>
<ChildChild />
</div>
)
}
export default Child;
app.js
import React,{ Component } from "react";
import PropTypes from "prop-types";
import Child from './ChildComponent';
export default class App extends Component{
// 父组件声明自己支持 context
static childContextTypes = {
color: PropTypes.string,
callback: PropTypes.func,
}
// 父组件提供一个函数,用来返回相应的 context 对象
getChildContext(){
return{
color: "red",
callback: this.callback.bind(this)
}
}
callback(msg){
console.log(msg);
}
render(){
return(
<div className="App">
{/* <Child title="Hello World!" callback = { this.callback.bind(this) }/> */}
<Child title="Hello World!" callback = { this.callback }/>
</div>
)
}
}
如果时父组件向子组件单向通信,可以使用变量,如果子组件想向父组件通信,可以由父组件提供一个回调函数,供子组件调用,回传参数。
在使用 context 时, 需要注意:
- 父组件要申明自己支持 context,并提供 context 中属性的 PropTypes
- 子组件也需要申明,提供其所需要的 context 属性的 PropTypes
- 父组件要提供要给 getChildContext 函数, 以返回一个初始的 context 对象。
- 如果组件中使用构造函数(constructor), 还需要在构造函数中传入第二个参数 context,并在super 调用父类构造函数传入 context, 否则会造成组件中无法使用 context。
constructor(props, context) {
super(props, context);
}
改变 context 对象
childChildComponent.js
import React,{ Component } from "react";
import PropTypes from "prop-types";
export default class ChildChild extends Component{
// 子组件声明自己需要使用 context
static contextTypes = {
color: PropTypes.string,
callback: PropTypes.func,
}
render(){
const style = { color: this.context.color }
const clickButtion = (msg) => {
return () => {
this.context.callback(msg);
}
}
return(
<div style = { style }>
ChildChild<br/>
<button onClick = { clickButtion("blue") }>child button2</button>
</div>
);
}
}
childComponent.js
import React from "react";
import ChildChild from './ChildChildComponent'
const Child = (props) => {
const clickButton = (msg) => {
return () => {
props.callback(msg)
}
}
return(
<div>
<h1>
{ props.title }
</h1>
<hr/>
<ChildChild />
</div>
)
}
export default Child;
app.js
import React,{ Component } from "react";
import PropTypes from "prop-types";
import Child from './ChildComponent';
export default class App extends Component{
constructor(props) {
super(props);
this.state = {
color:"red"
};
}
// 父组件声明自己支持 context
static childContextTypes = {
color: PropTypes.string,
callback: PropTypes.func,
}
// 父组件提供一个函数,用来返回相应的 context 对象
getChildContext(){
return{
color: this.state.color,
callback: this.callback.bind(this)
}
}
callback(color){
// 在Child中无法使用
// this.setState({
// color,
// })
console.log(color);
}
render(){
return(
<div className="App">
{/* <Child title="Hello World!" callback = { this.callback.bind(this) }/> */}
<Child title="Hello World!" callback = { this.callback }/>
</div>
)
}
}
非嵌套组件间通信
非嵌套组件, 就是没有任何包含关系的组件,包括兄弟组件以及不在同一个父级中的非兄弟组件。对于非嵌套组件,可以采用下面两种方式:
- 利用二者共同的父组件的 context 对象进行通信
- 使用自定义事件的方式
如果采用组件间共同的父级来进行中转,会增加子组件和父组件之间的耦合度,如果组件层次较深的话,找到二者公共的父组件不是一件容易的事,当然还是那句话,也不是不可以...
这里我们采用自定义事件的方式来实现非嵌套组件间的通信。
需要使用一个 events 包:
npm install events --save
新建一个ev.js, 引入 events 包,并向外提供一个事件对象,供通信时使用:
import { EventEmitter } from "events";
export default new EventEmitter();
app.js
import React,{ Component } from "react";
import BOne from './BOneComponent';
import BTwo from './BTwoComponent';
export default class App extends Component{
render(){
return(
<div className="App">
<BOne></BOne>
<BTwo></BTwo>
</div>
)
}
}
BOneComponent.js
import React,{ Component } from "react";
import emitter from "./ev"
export default class BOne extends Component{
constructor(props) {
super(props);
this.state = {
msg:null,
};
}
componentDidMount(){
// 声明一个自定义事件
// 在组件装载完成以后
this.eventEmitter = emitter.addListener("callMe",(msg)=>{
this.setState({
msg
})
});
}
// 组件销毁前移除事件监听
componentWillUnmount(){
emitter.removeListener(this.eventEmitter);
}
render(){
return(
<div>
{ this.state.msg }
我是非嵌套 1 号
</div>
);
}
}
BTwoComponent.js
import React,{ Component } from "react";
import emitter from "./ev"
export default class BTwo extends Component{
render(){
const cb = (msg) => {
return () => {
// 触发自定义事件
emitter.emit("callMe",msg)
}
}
return(
<div>
我是非嵌套 2 号
<button onClick = { cb("哈哈!我出现了!") }>点击我</button>
</div>
);
}
}
React 的生命周期
三个阶段:加载阶段(Mounting),更新阶段(Update),卸载阶段(UnMounting)
-
constructor: 组件被加载前最先调用,仅调用一次
-
componentwillmount: 组件初始渲染(render())前调用,仅调用一次
-
render: componentwillmount之后,componentDidMount之前, 渲染挂载组件
-
componentDidMount: render之后被调用,仅调用一次
-
shouldComponentUpdate(nextProps,nextState): 组件挂载后(render),接收到新得props和state时调用
-
componentWillUpdate: 在接收到新得props或者state,重新渲染前立刻调用, 在初始化渲染的时候不会被调用
-
componentDidUpdate: 重新渲染后调用,在初始化渲染时该方法不会被调用
-
componentWillUnmount: 组件被卸载前调用
参考
- 【简书】柏丘君.React中组件间通信的几种方式
- 【React Native中文网】sunnylqm.Props (属性)
- 【React Native中文网】sunnylqm.State (状态)
- 【React】react.入门教程:认识React
以上文章不分先后