React的核心思想就是:封装组件
目录
1、React语法格式
// App.js是在定义一个React组件(父组件)
import React, { Component, Fragment } from 'react';
import TodoItem from './TodoItem';
import './index.css';
// TodoList 继承 react的组件,就变成了TodoList组件
class TodoList extends Component {
// ES6的函数的构造函数,组件创建的一瞬间,constructor函数会自动被执行
constructor(props) {
// 初始化
super(props);
// 数据存放的位置
this.state = {
inputValue: '',
list: [
'列表是子组件,文本框和添加按钮是父组件',
'learn english',
'learn english',
'learn english'
]
}
this.inputChange = this.inputChange.bind(this);
// this.handleBtnClick = this.handleBtnClick.bind(this);
this.deleteItem = this.deleteItem.bind(this);
}
inputChange (e) { // input的change事件
this.setState({
inputValue: e.target.value
})
}
// 该组件的事件
handleBtnClick () { // 添加的点击事件
if (this.state.inputValue !== '') {
this.setState({
// ...是展开运算符,相当于
// ['learn react', 'learn english', 'hellow world']
list: [...this.state.list, this.state.inputValue],
inputValue: ''
})
}
}
handleItemClick (index) { // li标签的点击事件
const list = [...this.state.list]
list.splice(index, 1)
this.setState({
list: list
})
}
deleteItem (index, num) { // 获取子组件传递过来的值
console.log(index, num);
const list = [...this.state.list]
list.splice(index, 1)
this.setState({
list: list
})
}
bianliItem () {
return (
this.state.list.map((item, index) => {
return (
<TodoItem
delete={this.deleteItem}
key={index}
content={item}
index={index}/>
)
})
)
}
render() {
return (
<Fragment>
<div>
<input value={this.state.inputValue} onChange={this.inputChange} />
<button className='add-btn' style={{color: 'red'}} onClick={() => this.handleBtnClick()}>add</button>
</div>
{/* 遍历组件的两种方法: */}
{/* 1、使用方法遍历 */}
{/* <ul>{this.bianliItem()}</ul> */}
{/* 2、直接遍历在jsx代码中 */}
<ul>
{
this.state.list.map((item, index) => {
return (
<TodoItem
delete={this.deleteItem}
key={index}
content={item}
index={index}/>
)
})
}
</ul>
</Fragment>
)
}
}
export default TodoList;
2、jsx语法
jsx其实是语法糖
const title = <h1 className="title">Hello, world!</h1>;
可以转化成:
const title = React.createElement( 'h1', { className: 'title' }, 'Hello, world!' );
- React 的jsx语法创建的UI元素其实就是虚拟DOM,当执行了render函数之后,虚拟DOM变成了真正的DOM元素
- React 虚拟DOM的属性:
class: className
事件:onXXX eg: onClick、onChange
style: 就是style
其他的就是写的什么就是什么
3、 React.js diff算法
diff算法的定义:
每次更新DOM都是只更新需要更新的部分,极大地减少了DOM操作
diff算法的原则:
1、 对比当前真实的DOM和虚拟DOM,在对比过程中直接更新真实DOM
2、只对比同一层级的变化
4、 异步的setSate
React
组件每次调用setState
后会立即调用renderComponent
重新渲染组件,但现实情况是,我们可能会在极短时间内多次调用setState
,所以出于性能考虑,React
可能会把多个setState()
调用合成一个调用,所以setSate()
方法可能无法实现一个定时器,要解决这个问题,可以让setState()
接受一个函数而不是一个对象。这个函数用上一个state
做为第一个参数,将此次更新被应用时的props
做为第二个参数:
// Correct,次数的函数可以使箭头函数也可以是普通函数,实质是一样的
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
5、 组件
React定义组件的方式可以分为两种:函数和类,函数定义可以看做是类定义的一种简单形式。
React中改变
state
里面的值用setState
来改变,在改变数据的同时,也会更DOM,使数据双向展示在页面上
而setState
的操作是异步的,要想拿到实时的数据,可以在回调函数中做一些操作
- 定义组件
由于React的核心就是封装组件,所以React的每一个页面展示都是组件,不论是父组件还是子组件,声明组件的方式是一样的,组件对象中有钩子函数,自己定义的方法,和render
方法
class TodoItem extends Component {}
export default TodoItem;
6、 子组件和父组件之间的通讯
1、调用子组件:
创建:
class TodoItem extends Component {}
export default TodoItem;
引入(用到TodoItem
组件中):
import TodoItem from './TodoItem';
使用:
<TodoItem />
2、父组件向子组件传值:
父组件:
<TodoItem content={item}/>
content
就是父组件传递给子组件的值
子组件:
this.props.content 就是接受的父组件的值,但是此组件中要有constructor方法
render() {
return (
<div onClick={() => this.handlClick()}>
<span>{this.props.content}</span>
</div>
)
}
3、子组件向父组件传值
子组件:
子组件触发点击事件,执行handlClick
方法,而该方法中的操作是传递给父组件一个方法-delete
,值为子组件传递给父组件的值
render() {
return (
<div onClick={() => this.handlClick()}>
<span>{this.props.content}</span>
</div>
)
}
handlClick () {
this.props.delete(this.props.index, '22222222')
}
父组件:
delete
就是接收子组件传递过来的方法,在父组件中新定义一个方法来接收参数:
jsx:
<TodoItem
delete={this.deleteItem}
key={index}
content={item}
index={index}/>
函数:
deleteItem (index, num) { // 获取子组件传递过来的值
console.log(index, num);
const list = [...this.state.list]
list.splice(index, 1)
this.setState({
list: list
})
}
7、 组件的生命周期函数
声明周期函数可以很好的帮助我们处理组件中的数据,和一些操作
componentWillMount ------ 组件将要挂载时触发的函数
componentDidMount ------- 组件挂载完成时触发的函数
shouldComponentUpdate ------- 是否要更新数据时触发的函数
componentWillUpdate ------- 将要更新数据时触发的函数
componentDidUpdate ------- 数据更新完成时触发的函数
componentWillUnmount -------组件将要销毁时触发的函数
componentWillReceiveProps ------- 父组件中改变了props传值时触发的函数
8、UI框架(Ant Design简称antd)
- 下载:
npm install antd --save
- 按需引入:
import { Form, Icon, Input, Button } from 'antd';
import 'antd/dist/antd.css';
- antd表单的使用
import React, { Component,Fragment } from 'react';
import { Form, Icon, Input, Button } from 'antd';
import 'antd/dist/antd.css';
import './index.less';
class TodoList extends Component {
submitBtn = e => { // 提交按钮的点击事件
// 获取antd表单文本框的值
let username = this.props.form.getFieldValue('username');
console.log(username);
// 改变antd表单文本框的值
this.props.form.setFieldsValue({
username: '我是改变后的值'
})
}
render () {
// getFieldDecorator用于和表单进行双向绑定
const {getFieldDecorator} = this.props.form
return (
<Fragment>
<Form className="form_box">
<Form.Item>
{getFieldDecorator('username', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
placeholder="Username"
/>,
)}
</Form.Item>
<Form.Item>
<Button type="primary" className="submi_btn" onClick={this.submitBtn}>
确定
</Button>
</Form.Item>
</Form>
</Fragment>
)
}
}
// 使用getFieldDecorator的时候,导出这样导出才能使用getFieldDecorator
export default Form.create()(TodoList);
9、 React路由
1、安装:
cnpm i -S react-router-dom
2、 初始化路由
新建router.js
在router.js文件中写路由地址
import React from 'react'
import {
BrowserRouter, Route, Switch
} from 'react-router-dom'
import TodoList from '@/TodoList'
export default () => (
<BrowserRouter>
<Switch>
<Route path='/' component={TodoList}></Route>
</Switch>
</BrowserRouter>
)
3、将router.js
引入到index.js
入口文件中
import React from 'react';
import ReactDOM from 'react-dom';
// import TodoList from '@/TodoList';
import RouterDOm from '@/router.js'
// 原本render渲染的是TodoList,当引入路由之后,渲染路由,即可实现什么路由下面显示什么组件
ReactDOM.render(<RouterDOm />, document.getElementById('root'));
4、在组件中需要跳转路由的时候引入link跳转即可
// 引入:
import { Link } from 'react-router-dom';
// 在render中使用:
<div>
<Linkto='/Tab'>跳转到tab栏切换页面</Link>
</div>