react脚手架(create-react-app)
1.作用: 帮助我们生成一个通用的目录结构,并且已经将我们所需的工程环境配置好
2.依赖环境
脚手架都是使用node编写的,并且都是基于webpack的;
3.安装node
4.安装脚手架
npm install -g create-react-app
5.检查脚手架版本
create-react-app --version
创建项目
create-react-app 项目名称
跑项目
yarn start
目录
React组件化开发
类组件
定义:
- 组件的名称是大写字符开头的(无论类组件还是函数组件)
- 类组件需要继承自React.Component
- 类组件必须实现render函数
使用class定义一个组件:
constructor是可选的,我们通常在constructor中初始化一些数据
this.state中维护的就是我们组件内部的数据
render()方法是class组件中
函数式组件
/**
*
* 函数式组件的特点:
* 1.没有this对象
* 2.没有内部的状态
* 3.没有生命周期
*
*/
export default function App(){
return (
<div>我是function组件</div>
)
}
类组件
import React, { Component } from "react";
export default class App extends Component {
constructor() {
super();
this.state = {
message: 'hello'
}
}
render () {
return (
<div>
<div>app组件</div>
{/* alt+shift+f 代码格式化*/}
<h2>{this.state.message}</h2>
</div>
)
}
}
render函数的返回值
- React元素:通常通过JSX创建
- 数组或fragments
- portals:可以渲染子节点到不同的DOM子树中
- 字符串或数值类型
- 布尔类型或null:什么都不渲染
生命周期
很多事物从创建到销毁的整个过程,这个过程称之为生命周期。
constructor
如果不初始化state或不进行方法绑定,则不需要为React组件实现构造函数。
constructor中通常只做两件事情:
- 通过给this.state赋值对象来初始化内部的state
- 为事件绑定实例(this)
componentDidMount
componentDidMount()会在组件挂在后(插入DOM树中)立即调用
操作:
- 依赖于DOM的操作可以在这里进行
- 在此处发送网络请求就最好的地方(官方建议)
- 可以在此处添加一些订阅(会在componentWillUnmount取消订阅)
componentDidUpdate
componentDidUpdate()会在更新后会被立即调用,首次渲染不会执行此方法。
当组件更新后,可以在此处对DOM进行操作。
如果你对更新前后的props进行了比较,也可以选择在此处进行网络请求;(例如,当props未发生变化时,则不会执行网络请求)
componentWillUnmount
componentWillUnmount() 会在组件卸载及销毁之前直接调用。
在此方法中执行必要的清理操作;
例如:清除timer,取消网络请求或清楚
在componentDidMount()中创建的订阅等;
import React, { Component } from 'react'
class Cpn extends Component {
render () {
return <h2>我是cpn组件</h2>
}
componentWillUnmount () {
console.log('我调用了componentWillUnmount')
}
}
export default class App extends Component {
constructor() {
super();
this.state = {
count: 1,
isShow: true
}
console.log('执行了组件的constructor')
}
render () {
console.log('执行了组件的render函数')
return (
<div>
我是App组件
<h2>当前计数:{this.state.count}</h2>
<button onClick={e => { this.increment() }}>+1</button>
<hr />
<button onClick={e => { this.changeShow() }}>切换</button>
{this.state.isShow && <Cpn />}
</div>
)
}
increment () {
this.setState({
counter: this.state.counter + 1
})
}
changeShow () {
this.setState({
isShow: !this.state.isShow
})
}
componentDidMount () {
console.log('执行了componentDidMount方法')
}
componentDidUpdate (previProps,preState,snapshot) {
console.log('执行了componentDidUpdate方法')
}
}
组件通信
父->子 props
子->父 itemOnclock
1.父传子-类组件
import React, { Component } from 'react'
class ChilCpn extends Component{
// constructor(props){
// super(props);
// }
render(){
const {name,age,height} = this.props
return(
<h2>子组件展示数据:{name+' '+age+' '+height}</h2>
)
}
}
export default class App extends Component {
render() {
return (
<div>
<ChilCpn name='guo' age='18' height='1.55'/>
</div>
)
}
}
2.父传子-函数组件-- 参数验证
效果:
import React, { Component } from 'react'
import PropTypes from 'prop-types'
function ChildCpn(props){
const {name,age,height} = props
const {names} = props
return (
<div>
<h2>{name+' '+ age+' '+height}</h2>
{/*参数验证 */}
<ul>
{
names.map((item,index)=>{
return <li>{item}</li>
})
}
</ul>
</div>
)
}
ChildCpn.propTypes = {
name:PropTypes.string.isRequired, // 必传
age:PropTypes.number,
height:PropTypes.number,
names:PropTypes.array
}
// 默认值
ChildCpn.defaultProps = {
name:'wen',
age:20,
height:1.75,
names:['111']
}
export default class App extends Component {
render() {
return (
<div>
<ChildCpn name='guo' age={18} height={1.55} names={['abc','mab']}/>
<ChildCpn/>
</div>
)
}
}
类组件的参数校验
class ChildCpn extends Component{
// es6中class fields写法
static propTypes = {
}
static defaultProps = {
}
}
3.子组件传递父组件
import React, { Component } from 'react'
class CounterButton extends Component{
render(){
const {onClick} = this.props;
return <button onClick= {onClick}>+1</button>
}
}
export default class App extends Component {
constructor(props){
super(props);
this.state = {
counter:0
}
}
render() {
return (
<div>
<h2>当前计数{this.state.counter}</h2>
<button onClick= {e=>this.increment()}>+</button>
<CounterButton onClick={this.increment.bind(this)} />
<CounterButton onClick={e=>this.increment()} />
</div>
)
}
increment(){
this.setState({
counter:this.state.counter + 1
})
}
}
4.组件通信案例
APP.js
import React, { Component } from 'react'
import TabControl from "./TabControl"
export default class App extends Component {
constructor(props){
super(props);
this.titles = ['精选','流行','新款']
this.state = {
currentTitle:'精选'
}
}
render() {
const {currentTitle} = this.state
return (
<div>
<TabControl itemClick={index=>this.itemClick(index)} titles={this.titles}/>
<h2>{currentTitle}</h2>
</div>
)
}
itemClick(index){
console.log(index)
this.setState({
currentTitle:this.titles[index]
})
}
}
tabcontrol.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class TabControl extends Component {
constructor() {
super()
this.state = {
currentIndex: 1
}
}
render () {
const { titles } = this.props;
const { currentIndex } = this.state
return (
<div className="tab-control">
{
titles.map((item, index) => {
return (
<div key={index}
className={'tab-item ' + (index === currentIndex ? 'active' : '')}
onClick={e => this.itemClick(index)}>
<span>{item}</span>
</div>
)
})
}
</div>
)
}
itemClick (index) {
this.setState({
currentIndex: index
})
const {itemClick} = this.props
itemClick(index)
}
}
TabControl.propTypes = {
titles: PropTypes.array.isRequired
}