react
他是一个用于构建用户界面的 JavaScript 库
React-安装
- 安装 nodeJS
- 安装create-react-app
npm install -g create-react-app
创建项目
create-react-app myreact
// myreact 项目名称
启动项目
cd myreact
yarn start
// npm run start
默认项目地址:http://localhost:3000/
React文件结构和JSX语法
第一个react项目
打开 src/App.js 删除默认代码 得到 hello react
import React, { Component } from 'react';
//导入React和 React.Component
class App extends Component {
// App根组件继承 React.compoent
render() {
// 渲染 并返回一段html结构
return (
<div className="App">
<h1>你好react</h1>
</div>
);
}
}
export default App;
//导出默认 App根组件
JSX语法
JSX 是一个看起来很像 html 的 JavaScript 语法扩展。
js和html混合
1. 只能有一个根节点
return (
<div className="App">
<h1>你好react</h1>
</div>
);
// Classname="App" 就是根节点
2. 可以执行javascript表达式 {}
{1+1}
{i == 1 ? '对的!' : '错误的'}
3. 类名class 变成 className
<div className="App">
</div>
4. 行内样式 展开
var myStyle = {
"font-size": "14px",
"color": "#FF0000"
}
return (
<div className="App">
<h1 style={myStyle}>你好react</h1>
</div>
);
5. 注释 {/* 注释 */}
6. 数组里面可以直接写html节点
var arr = [
<h1>组件渲染</h1>,
<h1>虚拟dom</h1>
]
return (
<div className="App">
{arr}
</div>
);
组件
可以这么说,一个 React 应用就是构建在 React 组件之上的。
创建组件 Child.js
import React,{Component} from 'react'
export default class Child extends Component{
render(){
return (
<div className="child">
<h1>我是子组件</h1>
<hr/>
</div>
);
}
}
调用组件
01. 导入组件
import Child from './components/Child.js'
02 使用组件
return (
<div className="App">
<Child/>
<h1>App根组件</h1>
</div>
);
完成代码
import React, { Component } from 'react';
import Child from './components/Child.js'
// 导入组件
class App extends Component {
render() {
return (
<div className="App">
<Child/>
<h1>App根组件</h1>
</div>
);
}
}
export default App;
//导出默认 App根组件
React State(状态)
state 是组件的当前状态,可以把组件简单看成一个“状态机”,根据状态 state 呈现不同的 UI 展示。 一旦状态(数据)更改,组件就会自动调用 render 重新渲染 UI,这个更改的动作会通过 this.setState 方法来触发。
初始化组件 state
添加一个类构造函数来初始化状态 this.state
constructor() {
super(); //调用父对象构造函数
this.state={name:"dandan",age:18}
}
使用state
return (
<div className="App">
大家好我是{this.state.name}今年{this.state.age}岁了
</div>
);
完整代码
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state={name:"dandan",age:18}
}
render() {
return (
<div className="App">
大家好我是{this.state.name}今年{this.state.age}岁了
</div>
);
}
}
export default App;
React Props
state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。
传递prop给子组件
return (
<div className="App">
<Child name="dandan"/>
<Child name="段鹏"/>
<Child />
</div>
);
子组件使用props
import React, { Component } from 'react';
import Child from './components/Child'
class App extends Component {
render() {
return (
<div className="App">
<Child name="dandan"> </Child>
<Child name="段鹏"></Child>
<Child ></Child>
</div>
);
}
}
export default App;
完整代码
App.js
import React, { Component } from 'react';
import Child from './components/Child'
class App extends Component {
render() {
return (
<div className="App">
<Child name="dandan"> </Child>
<Child name="段鹏"></Child>
<Child ></Child>
</div>
);
}
}
export default App;
Child.js
import React,{Component} from 'react'
export default class Child extends Component{
render(){
return (
<div className="child">
<h1>我是子组件 我的名字是{this.props.name}</h1>
<hr/>
</div>
);
}
}
Child.defaultProps = {
name:"保密"
}
// props 默认值
事件处理
React 元素的事件处理和 DOM 元素类似
React 事件绑定属性的命名采用驼峰式写法,而不是小写。
如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM 元素的写法)
javascript写法
<button onclick="showMsg()">
按钮
</button>
react写法
<button onClick={showMsg}">
按钮
</button>
完整react代码
import React, { Component } from 'react';
class App extends Component {
showMsg(){
alert("来自react问候!");
}
render() {
return (
<div className="App">
<button onClick={this.showMsg}>按钮</button>
</div>
);
}
}
export default App;
setState 改变react状态
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {num:1}
}
addNum(){
this.setState({num:this.state.num+1})
}
render() {
return (
{this.state.num}
{this.addNum()}}>按钮
);
}
}
export default App;
用箭头函数是为了保证函数里面this的正确指向br 你也可以用bind方法
按钮
React 表单双向绑定
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {num:1}
}
changeNum(e){
this.setState({num:e.target.value})
}
render() {
return (
<div className="App">
<input type="text" value={this.state.num} onChange={this.changeNum.bind(this)}/>
<h1>{this.state.num}</h1>
</div>
);
}
}
export default App;
动态的添加更改class
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {bg:'red'}
}
changeClass(e){
this.setState(pre=>{
return ({bg:pre.bg==='red'?'blue':'red'});
})
}
render() {
return (
<div className="App">
<button className={this.state.bg} onClick={this.changeClass.bind(this)}>按钮</button>
</div>
);
}
}
export default App;
添加style
render() {
var css = {
borderRadius:"6px",
padding:"8px 16px",
color:'#fff',
background:'blue'
}
return (
<div className="App">
<button style={css}>按钮</button>
</div>
);
}
}
React 条件渲染
条件性地渲染一块内容
三目运算符号
render() {
var isLogin = true;
return (
<div className="App">
{isLogin?'欢迎您回来主人':'请登陆'}
</div>
);
}
& &运算符
在 JavaScript 中,true && expression 总是返回 expression,而 false && expression 总是返回 false。
因此,如果条件是 true,&& 右侧的元素就会被渲染,如果是 false,React 会忽略并跳过它。
render() {
var isLogin = false;
return (
<div className="App">
{isLogin &&'欢迎您回来主人'}
</div>
);
}
列表渲染
我们可以使用 JavaScript 的 map() 方法来创建列表。
初始化列表数据
constructor(props) {
super(props);
this.state={
list:[{name:'vue'},{name:'react'},{name:'angular'}]
}
}
map渲染列表
return (
<div className="App">
{this.state.list.map(
(item,index)=>{
return (
<div key={index}>{item.name}</div>
)
}
)}
</div>
);
完整代码
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state={
list:[{name:'vue'},{name:'react'},{name:'angular'}]
}
}
render() {
return (
<div className="App">
{this.state.list.map(
(item,index)=>{
return (
<div key={index}>{item.name}</div>
)
}
)}
</div>
);
}
}
export default App;
Key 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。
一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据的 id 作为元素的 key:
元素没有确定的 id 时,你可以使用他的序列号索引 index 作为 key:
组件生命周期
组件的生命周期可分成三个状态:
Mounting:已插入真实 DOM
Updating:正在被重新渲染
Unmounting:已移出真实 DOM
componentWillMount
在渲染前调用,在客户端也在服务端。一般用的比较少,更多的是用在服务端渲染
1、组件刚经历constructor,初始完数据
2、组件还未进入render,组件还未渲染完成,dom还未渲染
componentDidMount
在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。
组件第一次渲染完成,此时dom节点已经生成,可以在这里调用ajax请求,返回数据setState后组件会重新渲染
componentWillReceiveProps
在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
shouldComponentUpdate
返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
可以在你确认不需要更新组件时使用。
componentWillUpdate
在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
componentDidUpdate
在组件完成更新后立即调用。在初始化时不会被调用。
componentWillUnmount
在组件从 DOM 中移除之前立刻被调用。
class Demo extends Component {
constructor(props, context) {
//如果想(在组件其他地方是可以直接接收的)使用props或context,则需要以参数形式传入。
//只要组件存在constructor,就必要要写super,否则this指向会错误
super(props, context);
this.state = {
data: 1
};
},
componentWillMount () {
// 在组件挂载之前调用,且全局只调用一次。如果在这个钩子里可以setState,render后可以看到更新后的state,不会触发重复渲染。
// 该生命周期可以发起异步请求,并setState。(React v16.3后废弃该生命周期,可以在constructor中完成设置state)
// 不推荐在这里发起ajax请求,若返回数据为空,则容易造成界面空白,影响渲染效果
},
componentDidMount () {
//组件第一次渲染完成,此时dom节点已经生成,可以在这里调用ajax请求,返回数据setState后组件会重新渲染
},
componentWillReceiveProps (nextProps) {
// 在接受父组件改变后的props需要重新渲染组件时用到的比较多
// 通过对比nextProps和this.props,将nextProps setState为当前组件的state,从而重新渲染组件
nextProps.data !== this.props.data && this.setState({
data: nextProps.data
},() => {
console.log("new data...");
});
},
shouldComponentUpdate (nextProps, nextState) {
// react性能优化非常重要的一环。
// 组件接受新的state或者props时调用,我们可以设置在此对比前后两个props和state是否相同,
// 如果相同则返回false阻止更新,因为相同的属性状态一定会生成相同的dom树,
// 这样就不需要创造新的dom树和旧的dom树进行diff算法对比,节省大量性能,尤其是在dom结构复杂的时候。
},
componentWillUpdate (nextProps, nextState) {
// 组件初始化时不调用,只有在组件发生更新需要重新渲染时才调用
},
componentDidUpdate (prevProps, prevState) {
// 组件初始化时不调用,组件更新渲染完成后调用,此时dom节点加载完成,可以获取到dom节点。
// react只会在第一次初始化成功会进入componentDidmount,
// 之后每次重新渲染后都会进入这个生命周期,这里可以拿到prevProps和prevState,即更新前的props和state。
// 该钩子内setState有可能会触发重复渲染,需要谨慎判断,否则会进入死循环
},
render () {
return (
<div>This is Demo!</div>
);
},
componentWillUnmount () {
// 组件将要卸载时调用,一些事件监听和定时器需要在此时清除。
},
componentDidCatch (error, info) {
//React 16 中引入,用来 捕获组件的错误。
//如果 render() 函数抛出错误,则会触发该函数。
//错误在渲染阶段中被捕获,但在事件处理程序中不会被捕获。
}
}
我们应当将AJAX 请求放到 componentDidMount 函数中执行,主要原因有下:
React 可能会多次频繁调用 componentWillMount,如果我们将 AJAX 请求放到 componentWillMount 函数中,那么显而易见其会被触发多次,自然也就不是好的选择。
如果我们将 AJAX 请求放置在生命周期的其他函数中,我们并不能保证请求仅在组件挂载完毕后才会要求响应。如果我们的数据请求在组件挂载之前就完成,并且调用了setState函数将数据添加到组件状态中,对于未挂载的组件则会报错。而在 componentDidMount 函数中进行 AJAX 请求则能有效避免这个问题。
componentDidMount() {
this.getMovie();
}
getMovie(){
fetch("http://www.endata.com.cn/API/GetData.ashx",{
method:"post",
body:"MethodName=BoxOffice_GetPcHomeList",
headers:{"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}
})
.then(res=>res.json())
.then(res=>{
console.log(res)
})
}
子组件调用父组件方法|向父组件传递参数
父亲传一个函数props
import React, { Component } from 'react';
import Child from './components/Child'
class App extends Component {
showMsg(msg){
alert(msg);
}
render() {
return (
<div className="App">
<Child name="曾庆林" fun={this.showMsg}></Child>
</div>
);
}
}
export default App;
子组件在箭头函数执行props
import React,{Component} from 'react' export default class Child extends Component{
render(){
return (
<div className="child">
<h1>我是子组件 我的名字是{this.props.name}</h1>
<button onClick={()=>{this.props.fun('我爱我的祖国')}}>调用父亲函数方法</button>
<hr/>
</div>
);
}
}