1 认识
由facebook开发,只提供了MVC中的V。
优势:
①是组件化的,将js与html标签结合到一起
②单向数据流
③虚拟DOM树
下面为一段代码,初步认识react
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
</div>
<script type="text/babel">
class HelloMessage extends React.Component {
render() {
return (
<div>
Hello {this.props.name}
</div>
);
}
}
ReactDOM.render(
<HelloMessage name="Taylor" />,
document.getElementById('app')
);
</script>
<script src="https://cdn.bootcss.com/react/16.10.2/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.10.2/umd/react-dom.development.js"></script>
<script src="https://cdn.bootcss.com/babel-standalone/7.0.0-beta.3/babel.js"></script>
</body>
</html>
2 create-react-app
有以下几个步骤
npm install -g create-react-app
create-react-app my-app
cd my-app
npm start
也可以打包
yarn build
3 第一个组件
首先引入bootstrap,在index.html里面
<link href="https://cdn.bootcss.com/twitter-bootstrap/4.0.0-beta.2/css/bootstrap.css" rel="stylesheet">
然后在App.js里面写代码
import React,{Component} from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render(){
return (
<div className="container">
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<h1>hello world</h1>
</div>
</div>
</div>
)
}
}
export default App;
4 剩下的内容
在src下新建一个components的目录,然后把组件都放到里边。我们新建一个header.js和home.js,内容分别为
import React,{Component} from 'react';
class header extends Component {
render(){
return (
<div className="container">
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<h1>header</h1>
</div>
</div>
</div>
)
}
}
export default header;
import React,{Component} from 'react';
class home extends Component {
render(){
return (
<div className="container">
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<h1>home</h1>
</div>
</div>
</div>
)
}
}
export default home;
然后在app.js里引用
import React,{Component} from 'react';
import Header from './components/header.js'
import Home from './components/home.js'
class App extends Component {
render(){
let content='';
if(true){
content='hello'
}
return (
<div className="container">
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<Header/>
</div>
</div>
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<h1>hello world</h1>
</div>
</div>
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<Home/>
{content}
{true ? 'hello':'world'}
</div>
</div>
</div>
)
}
}
export default App;
动态数据:{}里面可以用三元运算符
props父组件向子组件传参和类型检查:
App.js
import React,{Component} from 'react';
import Header from './components/header.js'
import Home from './components/home.js'
class App extends Component {
render(){
let content='';
if(true){
content='hello'
}
const user={
name:'Anna',
hobbies:["sports","read"]
}
return (
<div className="container">
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<Header/>
</div>
</div>
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<h1>hello world</h1>
</div>
</div>
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<Home name={"Max"} age={12} user={user}>
<p>I am child</p>
</Home>
{content}
{true ? 'hello':'world'}
</div>
</div>
</div>
)
}
}
export default App;
home.js
import React,{Component} from 'react';
import ProTypes from 'prop-types';
class home extends Component {
render(){
console.log(this.props);
return (
<div className="container">
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<div>name:{this.props.name}</div>
<div>age:{this.props.age}</div>
<h4>hobbies</h4>
<ul>
{this.props.user.hobbies.map((hobby)=><li key={hobby}>{hobby}</li>)}
</ul>
<div>{this.props.children}</div>
</div>
</div>
</div>
)
}
}
// 检验数据类型
home.propTypes={
name:ProTypes.string,
age:ProTypes.number,
user:ProTypes.object,
children:ProTypes.element.isRequired
}
export default home;
state:更新DOM,只是部分渲染
import React,{Component} from 'react';
import ProTypes from 'prop-types';
class home extends Component {
constructor(props){
super(props);
this.state={
age:props.age
}
}
onMakeMe(){
this.setState({
age:this.state.age + 1
})
}
render(){
console.log(this.props);
return (
<div className="container">
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<div>name:{this.props.name}</div>
<div>age:{this.state.age}</div>,
<h4>hobbies</h4>
<ul>
{this.props.user.hobbies.map((hobby)=><li key={hobby}>{hobby}</li>)}
</ul>
<div>{this.props.children}</div>
<button onClick={()=>{this.onMakeMe()}} className="btn btn-primary">click me</button>
</div>
</div>
</div>
)
}
}
// 检验数据类型
home.propTypes={
name:ProTypes.string,
age:ProTypes.number,
user:ProTypes.object,
children:ProTypes.element.isRequired
}
export default home;
无状态组件:又叫函数式组件,指无状态改变的组件,没有生命周期
import React from 'react';
// 第一种写法
// class header extends Component {
// render{
// return (
// <div className="container">
// <div className="row">
// <div className="col-xs-1 col-xs-offset-11">
// <h1>header</h1>
// </div>
// </div>
// </div>
// )
// }
// }
// 第二种写法,一般适用于无需state,即不需要处理用户的输入和不需要用到生命周期函数
//好处:1 不需要声明类,可以避免大量的比如extends和constructor的代码
// 2 不需要声明this关键字
const header = (props)=> {
return (
<div className="container">
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<h1>header</h1>
</div>
</div>
</div>
)
}
export default header;
如果后续又想改成有状态的组件,可以改。以后学。
子组件向父组件传参:
子组件:
import React,{Component} from 'react';
import ProTypes from 'prop-types';
class home extends Component {
handleGreet(){
this.props.greet(this.state.age)
}
render(){
console.log(this.props);
return (
<div className="container">
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<button onClick={this.props.greet} className="btn btn-primary">greet</button>
<button onClick={this.handleGreet.bind(this)} className="btn btn-primary">handlegreet</button>
</div>
</div>
</div>
)
}
}
export default home;
父组件:
import React,{Component} from 'react';
import Header from './components/header.js'
import Home from './components/home.js'
class App extends Component {
onGreet(age){
alert("hello!"+age)
}
render(){
return (
<div className="container">
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<Header/>
</div>
</div>
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<h1>hello world</h1>
</div>
</div>
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<Home name={"Max"} age={12} user={user} greet={this.onGreet}>
<p>I am child</p>
</Home>
{content}
{true ? 'hello':'world'}
</div>
</div>
</div>
)
}
}
export default App;
兄弟组件间传值和数据双向绑定、生命周期
app.js
import React,{Component} from 'react';
import Header from './components/header.js'
import Home from './components/home.js'
class App extends Component {
constructor(){
super();
this.state={
homeLink:'Home',
homeMounted:true
}
}
onGreet(age){
alert("hello!"+age)
}
onChangeLinkName(newName){
this.setState({
homeLink:newName
})
}
onChangeHomeMounted(){
this.setState({
homeMounted:!this.state.homeMounted
})
}
render(){
let content='';
if(true){
content='hello'
}
const user={
name:'Anna',
hobbies:["sports","read"]
}
let homeCap="";
if(this.state.homeMounted){
homeCap=(
<Home
name={"Max"}
age={12}
user={user} g
greet={this.onGreet}
initialName={this.state.homeLink}
changeLink={this.onChangeLinkName.bind(this)}>
<p>I am child</p>
</Home>);
}
return (
<div className="container">
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<Header homeLink={this.state.homeLink}/>
</div>
</div>
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<h1>hello world</h1>
</div>
</div>
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
{homeCap}
{content}
{true ? 'hello':'world'}
</div>
</div>
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<button onClick={this.onChangeHomeMounted.bind(this)} className="btn btn-primary">component</button>
</div>
</div>
</div>
)
}
}
export default App;
home.js
import React,{Component} from 'react';
import ProTypes from 'prop-types';
class home extends Component {
constructor(props){
super(props);
this.state={
age:props.age,
homeLink:props.initialName
}
}
onMakeMe(){
this.setState({
age:this.state.age + 1
})
}
handleGreet(){
this.props.greet(this.state.age)
}
onChangeLink(){
this.props.changeLink(this.state.homeLink)
}
onHandleChange(event){
this.setState({
homeLink:event.target.value
})
}
componentWillMount(){
console.log('will mount')
}
componentDidMount(){
console.log('did mount')
}
componentWillReceiveProps(nextProps){
console.log('will receive props',nextProps)
}
shouldComponentUpdate(nextProps,nextState){
console.log('should upstate',nextProps,nextState)
}
componentWillUpdate(nextProps,nextState){
console.log('will upstate',nextProps,nextState)
}
componentDidUpdate(prevProps,prevState){
console.log('did upstate',prevProps,prevState)
}
componentWillUnmount(){
console.log('will unmount')
}
render(){
console.log(this.props);
return (
<div className="container">
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<div>name:{this.props.name}</div>
<div>age:{this.state.age}</div>,
<h4>hobbies</h4>
<ul>
{this.props.user.hobbies.map((hobby)=><li key={hobby}>{hobby}</li>)}
</ul>
<div>{this.props.children}</div>
<button onClick={()=>{this.onMakeMe()}} className="btn btn-primary">click me</button>
<hr/>
<button onClick={this.handleGreet.bind(this)} className="btn btn-primary">handlegreet</button>
<hr/>
<input
type=""
defaultValue={this.props.initialName}
value={this.state.initialName}
onChange={(event)=>this.onHandleChange(event)}/
>
<button onClick={this.onChangeLink.bind(this)} className="btn btn-primary">Change Header Link</button>
</div>
</div>
</div>
)
}
}
// 检验数据类型
home.propTypes={
name:ProTypes.string,
age:ProTypes.number,
user:ProTypes.object,
children:ProTypes.element.isRequired,
initialName:ProTypes.string
}
export default home;
header.js
import React from 'react';
const header = (props)=> {
return (
<div className="container">
<div className="row">
<div className="col-xs-1 col-xs-offset-11">
<h1>header----{props.homeLink}</h1>
</div>
</div>
</div>
)
}
export default header;
组件的生命周期可分成三个状态:
- Mounting:已插入真实 DOM(1,2)
- Updating:正在被重新渲染(3,4,5,6)
- Unmounting:已移出真实 DOM(7)
生命周期的方法有:
-
componentWillMount 在渲染前调用,在客户端也在服务端。
-
componentDidMount : 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。
-
componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
-
shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
可以在你确认不需要更新组件时使用。 -
componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
-
componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。
-
componentWillUnmount在组件从 DOM 中移除之前立刻被调用。