介绍:
React是一个用于构建用户界面的javaScript库,起源于facebook的内部项目,在13年f进行开源
17版本官网:React – A JavaScript library for building user interfaces
18版本官网:React 官方中文文档
特点:
- 声明式编码
- 组件化编码
- React Native 编写原生应用
- 高效(优秀的Diffing算法)
一、基础
主要核心,依赖下面四个文件<!-- 引入核心库。全局出现React对象--> <script type="text/javascript" src="./React-js/16.8/react.development.js"></script> <!-- 用于支持react操作DOM。全局出现ReactDOM对象--> <script text="text/javascript" src="./React-js/16.8/react-dom.development.js"></script> <!-- 用于将jsx转换为js --> <script text="text/javascript" src="./React-js/16.8/babel.min.js"></script> <!-- 用于对组件标签属性进行限制。全局出现PropTypes对象 --> <script src="./React-js/16.8/prop-types.js"></script>
1、基本使用
1.1、虚拟dom
关于虚拟DOM:
- 本质是object类型的对象(一般对象)
- 虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部在用,无需真实DOM 上:那么多的属性。
- 虚拟DOM最终会被React转化为真实DOM。呈现在页面上
<body>
<div id="test"></div>
<!-- 引入核心库 -->
<script type="text/javascript" src="./React-js/16.8/react.development.js"></script>
<!-- 用于支持react操作DOM -->
<script text="text/javascript" src="./React-js/16.8/react-dom.development.js"></script>
<!-- 用于将jsx转换为js -->
<script text="text/javascript" src="./React-js/16.8/babel.min.js"></script>
<!-- 一定是babel -->
<script type="text/babel">
// 创建虚拟dom
const VDOM = <h1>Hello.React</h1>
const VDOM2 = <h1>----------------</h1>
// 渲染虚拟DOM到页面(后面的会替换之前)
ReactDOM.render(VDOM,document.getElementById('test'))
ReactDOM.render(VDOM2,document.getElementById('test'))
</script>
</body>
2.2、JSX写法
1、全称: JavaScript XML。
2、react定义的一种类似于XML的JS扩展语法: JS + XML本质是React.createElement(component, props, ...children)方法的语法糖
3、作用: 用来简化创建虚拟DOM
写法:var ele = <h1>Hello JSX!</h1>
注意1:它不是字符串, 也不是HTML/XML标签
注意2:它最终产生的就是一个JS对象
4、jsx语法规则:
- 定义虚拟DOM时,不要写引号。
- 标签中混入JS表达式时要用{}-
- 样式的类名指定不要用class,要用className.
- 内联样式,要用style={ {key : value}}的形式去写。
- 只有一个根标签
- 标签必须闭合
- 标签首字母
(1).若小写字母开头,则将改标签转为htm1中同名元素,若htm1中无该标签对应的同名元素,则报错。
(2).若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。
<body>
<div id="test"></div>
<!-- 引入核心库 -->
<script type="text/javascript" src="./React-js/16.8/react.development.js"></script>
<!-- 用于支持react操作DOM -->
<script text="text/javascript" src="./React-js/16.8/react-dom.development.js"></script>
<!-- 用于将jsx转换为js -->
<script text="text/javascript" src="./React-js/16.8/babel.min.js"></script>
<!-- js写法 -->
<script type="text/javascript">
// 创建虚拟dom
const VDOM = React.createElement('h1',{id:'title'},React.createElement('span',{},'js写法'))
// 渲染虚拟DOM到页面(后面的会替换之前)
ReactDOM.render(VDOM, document.getElementById('test'))
</script>
<!-- jsx写法 -->
<script type="text/babel">
const data = ['抽烟','喝酒','烫头']
const obj = {name1:'抽烟',name2:'喝酒',name3:'烫头'}
const myId = 'song'
const myData = 'HELLO'
const VDOM = (
<div>
<h1 className="box" id={myId}>
<span style={
{ color: 'red', fontSize: '40px' }}>{myData.toLocaleLowerCase()}</span>
</h1>
<input type="text" />
<ul>
{
// data // 直接使用数组,会自动遍历
// obj // 对象,会报错
data.map((item,i)=><li key={i}>{item}</li>)
}
</ul>
</div>
)
// 渲染虚拟DOM到页面(后面的会替换之前)
ReactDOM.render(VDOM, document.getElementById('test'))
</script>
</body>
2、函数式组件
<script type="text/babel">
// 定义函数组件
function Demo() {
console.log(this); // 经过babel转化开启严格模式,this没有明确的调用,所以为undefined
return <h2>函数定义的组件</h2>
}
// 渲染组件到页面
ReactDOM.render(<Demo />, document.getElementById('test'))
/*
执行了ReactDOM.render( <MyComponent/>.......之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOW转为真实DOM,随后呈现在页面中。
*/
</script>
3、类组件
<script type="text/babel">
// 定义类组件
class Demo extends React.Component{
render(){
// render:类的原型对象上(可在浏览器控制台输入Demo回车测试),供实例使用
// this指向Demo的实例对象。俗称:组件对象或组件实例对象
console.log('render中this',this);
return (
<h2>类定义的组件</h2>
)
}
}
// 渲染组件到页面
ReactDOM.render(<Demo />, document.getElementById('test'))
/*
执行了ReactDOM.render( <MyComponent/>.......之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用原型上的render方法
3.将返回的虚拟DOW转为真实DOM,随后呈现在页面中。
*/
</script>
3.1、constructor
<script type="text/babel">
// 定义类组件
class Weather extends React.Component {
// 构造器是否接受props,是否传递super,取决于:是否需要在构造器中通过this访问props
// 若是写了构造器,不给super传props则,在构造器中拿不到props。为undefined
constructor(props) { // 构造器只调用一次
// super(props)
super()
console.log(this.props);
}
render() {
return (
<h2 ></h2>
)
}
}
const p = { name: 'tom', age: 18, sex: '女' }
// 渲染组件到页面
ReactDOM.render(<Weather {...p} />, document.getElementById('test'))
</script>
4、组件的三大核心
4.1、state:存放状态
<script type="text/babel">
// 定义类组件
class Weather extends React.Component {
constructor(props) { // 构造器只调用一次
super(props)
// 初始化状态
this.state = {
isHot: false,
wind: '大风'
}
// 改变原型上的demo的this指向,并把原型上的demo赋值到实例上的demo上。处理下面this为undefind
this.demo = this.demo.bind(this)
}
render() { // 调用1+n次。1:初始化 n:状态更新的次数
return (
<h2 onClick={this.demo}>今天天气{this.state.isHot ? '炎热' : '很冷'}</h2>
)
}
demo() {
// demo放在哪里? Weather的原型对象上,供实例使用
//由于demo是作为onclick的回调,所以不是通过实例调用的,是直接调用
//类中的方法默认开启了局部的严格模式,所以demo中的this为undefined
console.log('this', this); // undefind
// 不能直接修改值。数据虽然变化,但页面不刷新
// this.state.isHot = !this.state.isHot
// 注意:需要通过setState方法来修改状态
this.setState({ isHot: !this.state.isHot })
}
}
// 渲染组件到页面
ReactDOM.render(<Weather />, document.getElementById('test'))
function demo() {
// console.log('被点击');
alert('被点击')
}
</script>
(1)、state简写
<script type="text/babel">
// 定义类组件
class Weather extends React.Component {
// 初始化状态
state = { isHot: false, wind: '大风' }
render() {
return (
<h2 onClick={this.demo}>今天天气{this.state.isHot ? '炎热' : '很冷'}</h2>
)
}
// 自定义方法---需要赋值语句的形式+箭头函数
demo = ()=> {
console.log('this', this); // undefind
this.setState({ isHot: !this.state.isHot })
}
}
// 渲染组件到页面
ReactDOM.render(<Weather />, document.getElementById('test'))
</script>
<!--
1、组件中 render方法中的this 为组件实例对象-
2、组件自定义的方法中this为 undefined,如何解决?
a.强制绑定this:通过函数对象bind
b.箭头函数
3、状态数据,不能直接修改或更新
-->
4.2、props:接收参数
<script type="text/babel">
// 定义类组件
class Weather extends React.Component {
render() {
console.log(this);
return (
<ul>
<li>姓名:{this.props.name}</li>
<li>性别:{this.props.sex}</li>
<li>年龄:{this.props.age}---{this.props.flag}</li>
</ul>
)
}
}
const p = { name: 'tom', age: 18, sex: '女' }
// 渲染组件到页面
ReactDOM.render(<Weather {...p} flag={666}/>, document.getElementById('test'))
</script>
(1)、props限制
<!-- 用于对组件标签属性进行限制。全局出现PropTypes对象 -->
<script src="./React-js/16.8/prop-types.js"></script>
<script type="text/babel">
// 定义类组件
class Weather extends React.Component {
render() {
console.log(this);
// 注意:props是只读的
this.props.speak()
return (
<ul>
<li>姓名:{this.props.name}</li>
<li>性别:{this.props.sex}</li>
<li>年龄:{this.props.age+1}-----</li>
</ul>
)
}
}
// propTypes:给类加规则
Weather.propTypes = {
// 在15以及以下版本
// name:React.PropTypes.string
// 16版本及以上,需要通过引入PropTypes对象
name:PropTypes.string,
sex:PropTypes.string,
age:PropTypes.number.isRequired, // isRequired。必传
speak: PropTypes.func // 限制为函数
}
// 设置不传时的默认值
Weather.defaultProps = {
sex:'我是默认值'
}
// 渲染组件到页面
ReactDOM.render(<Weather name="song" age={666} speak={fun}/>, document.getElementById('test'))
function fun (){
console.log('我是函数');
}
</script>
(2)、简写
<script type="text/babel">
class Weather extends React.Component {
// 写在类里面,相当于给类加属性
static propTypes = {
name: PropTypes.string,
sex: PropTypes.string,
age: PropTypes.number.isRequired, // isRequired。必传
speak: PropTypes.func // 限制为函数
}
static defaultProps = {
sex: '我是默认值'
}
render() {
console.log(this);
// 注意:props是只读的
this.props.speak()
return (
<ul>
<li>姓名:{this.props.name}</li>
<li>性别:{this.props.sex}</li>
<li>年龄:{this.props.age + 1}-----</li>
</ul>
)
}
}
// 渲染组件到页面
ReactDOM.render(<Weather name="song" age={666} speak={fun} />, document.getElementById('test'))
function fun() {
console.log('我是函数');
}
</script>
(3)、在函数组件的使用
// 定义函数组件
function Weather(props) {
console.log(this, props); // 经过babel转化开启严格模式,this没有明确的调用,所以为undefined
return (
<ul>
<li>姓名:{props.name}</li>
<li>性别:{props.sex}</li>
<li>年龄:{props.age + 1}-----</li>
</ul>
)
}
Weather.propTypes = {
name: PropTypes.string,
sex: PropTypes.string,
age: PropTypes.number.isRequired,
}
Weather.defaultProps = {
sex: '我是默认值'
}
// 渲染组件到页面
ReactDOM.render(<Weather name="song" age={666} />, document.getElementById('test'))
4.3、refs与事件处理
(1)、字符串形式的ref
class Demo extends React.Component{
// 展示左侧输入框的数据
showData = ()=>{
alert(this.refs.inp1.value)
}
// 展示左侧输入框的数据
showData2 = ()=>{
alert(this.refs.inp2.value)
}
render(){
return(
<div>
<input ref="inp1" type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点击提示左侧的数据</button>
<input ref="inp2" onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
}
(2)、回调函数形式的ref
class Demo extends React.Component {
state = { isHot: true }
// 展示左侧输入框的数据
showData = () => {
alert(this.inp1.value)
}
changWeacter = () => this.setState({ isHot: !this.state.isHot })
/**
* ref若是以下面内联函数的方式定义,它在更新过程中会别执行两次,
* 第一次传入参数为null,第二次才是DOM元素
* 因为每次渲染时都会创建新的函数实例,所以React清空旧的ref,被设置新的、
* *
* 不过可以把回调函数定义成class的绑定函数的方式可以避免,
*
*/
saveInp = (c)=>{
this.inp2 = c; console.log('绑定函数@', c)
}
render() {
const { isHot } = this.state
//
return (
<div>
<h1>今天天气{this.state.isHot ? '炎热' : '很冷'}</h1>
{/* c:input标签。相当于往Demo身上添加了inp1属性,把input标签赋值给它。内联函数方式*/}
<input ref={c => { this.inp1 = c; console.log('@', c) }} type="text" placeholder="点击按钮提示数据" />
{/* 使用class绑定函数的方式 */}
<input ref={this.saveInp} type="text" placeholder="点击按钮提示数据" />
<button onClick={this.showData}>点击提示左侧的数据</button>
<button onClick={this.changWeacter}>点击切换天气</button>
</div>
)
}
}
(3)、API形式的ref
class Demo extends React.Component {
/** React.createRef
* 存放被ref标识的节点,但只能单独存一个
*/
myRef = React.createRef()
myRef2 = React.createRef()
// 展示左侧输入框的数据
showData = () => {
console.log(this.myRef,this.myRef2);
}
render() {
//
return (
<div>
<input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />
<input ref={this.myRef2} type="text" placeholder="点击按钮提示数据" />
<button onClick={this.showData}>点击提示左侧的数据</button>
</div>
)
}
}
(4)、事件处理
class Demo extends React.Component {
/**
* 1、通过onXxx属性指定事件处理函数(注意大小写)
* (1)React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 ---为了处理兼容
* (2)React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) --- 为了高效
* 2、通过event.target得到发生事件的DOM元素对象
*/
myRef = React.createRef()
myRef2 = React.createRef()
// 展示左侧输入框的数据
showData = () => {
console.log(this.myRef, this.myRef2);
}
showData2 = (e) => {
console.log(e.target.value);
}
render() {
//
return (
<div>
<input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />
<button onClick={this.showData}>点击提示左侧的数据</button>
<input onBlur={this.showData2} type="text" placeholder="失去焦点提示数据" />
</div>
)
}
}
(5)、函数柯里化与高阶函数
/**
* *高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。
* 1.若A雨数,接收的参数是一个函数,那么A就可以称之为高阶函数。
* 2.若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。
* 常见的高阶函数有: Promise、setTimeout、arr.map()等等
*
* *函数的柯里化: 通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。
*/
// 普通写法
function sum(a,b,c){
return a+b+c
}
const res = sum(1,2,3)
// 柯里化写法
function sum(a){
return (b)=>{
return (c)=>{
return a+b+c
}
}
}
const res = sum(1)(2)(3)
/* 普通写法: */
// class Demo extends React.Component {
// state = {
// username:'',
// password:''
// }
// // 保存
// saveUsername = (e)=>{
// this.setState({username:e.target.value})
// }
// savePassword = (e)=>{
// this.setState({password:e.target.value})
// }
// // 展示左侧输入框的数据
// handleSubmit = (e)=>{
// e.preventDefault() // 阻止默认行为
// const {username,password } = this.state
// console.log('用户名密码:',username,password);
// }
// render() {
// //
// return (
// <form onSubmit={this.handleSubmit}>
// 用户名:<input onChange={this.saveUsername} type="text" />
// 密码:<input onChange={this.savePassword} type="password" />
// <button>登录</button>
// </form>
// )
// }
// }
/* 柯里化写法: */
// class Demo extends React.Component {
// state = {
// username: '',
// password: ''
// }
// // 保存。柯里化写法
// saveData = (dataType) => {
// console.log('dataType', dataType);
// return (e) => {
// this.setState({ [dataType]: e.target.value })
// }
// }
// handleSubmit = (e) => {
// e.preventDefault() // 阻止默认行为
// const { username, password } = this.state
// console.log('用户名密码:', username, password);
// }
// render() {
// //
// return (
// <form onSubmit={this.handleSubmit}>
// 用户名:<input onChange={this.saveData('username')} type="text" />
// 密码:<input onChange={this.saveData('password')} type="password" />
// <button>登录</button>
// </form>
// )
// }
// }
/* 不使用柯里化写法: */
class Demo extends React.Component {
state = {
username: '',
password: ''
}
// 保存。
saveData = (dataType, data) => {
console.log('dataType', dataType, data);
this.setState({ [dataType]: data })
}
handleSubmit = (e) => {
e.preventDefault() // 阻止默认行为
const { username, password } = this.state
console.log('用户名密码:', username, password);
}
render() {
//
return (
<form onSubmit={this.handleSubmit}>
用户名:<input onChange={(e) => this.saveData('username', e.target.value)} type="text" />
密码:<input onChange={(e) => this.saveData('password', e.target.value)} type="password" />
<button>登录</button>
</form>
)
}
}