React 基础笔记
概览
React是一个声明式,高效且灵活的用于构建用户界面的JavaScript库。可以将一些简短、独立的代码片段组合成复杂的UI界面,这些片段被称为“组件”。
React 大体包含下面这些概念:
- 组件
- JSX
- Virtual DOM
- Data Flow
组件
可以将UI 拆分为独立且复用的代码片段,每部分都可独立维护。
组件,从概念上类似于JavaScript函数。它接受任意的参数(即 “props”),并返回用于描述页面展示内容的React 元素。
自定义组件命名:必须以大写字母开头,React 会将以小写字母开头的组件视为原生DOM标签。
import React from 'react'; // React 的核心库
import ReactDOM from 'react-dom'; // 提供与 DOM 相关的功能
class ShoppingList extends React.Component {
render() {
return (
<div className="shopping-list">
<h1>Shopping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}
ReactDOM.render(
<ShoppingList name="Mark" />,
document.getElementById('root')
);
React 应用都是构建在组件之上。ShoppingList就是一个React 组件类型,ReactDOM.render 函数会将组件方到页面上的某个节点元素中。(render 返回了一个 React 元素 ,这是一种对渲染内容的轻量级描述。)
大多数 React 应用只会调用一次 ReactDOM.render()。
其中props(是 properties 的简写) 是组件包含的两个核心概念之一,另一个是state。
props
props接收一些其他组件的参数(比如上方的 name ),来配置组件,所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。
state
state 来实现所谓“记忆”的功能。可以通过 React 组件的构造函数中设置 this.state;this.state 应该被视为一个组件的私有属性。
修改this.state值需要通过this.setState方法赋值,有些 props 值或 state 值可能是异步更新的,使用对象赋值的方式更改 state 可能无效,可使用回调传参方式更新
this.setState( (state,props)=> ({count:state.count + props.count}) );
类组件
通过
class语法来定义组件,必须包含render()方法,并且继承于React.Component。
类组件必须包含render(),并且return 只能返回一个父元素(类似vue中的template中必须要有一个父元素)。
class Square extends React.Component {
/**
* @name constructor
* @param {*} props
* 每次定义子类的构造函数时,都必须调用 super 方法。
* 因此,在所有含有构造函数的React组件中,构造函数必须以super(props)开头
* state 保存着组件中的数据 类似 vue 中的 data 属性
*/
constructor(props) {
super(props);
this.state = {
value:null
};
}
render() {
return (
<button className="square" onClick = {()=>{this.setState({value:'X'})}
}>
{this.state.value}
</button>
);
}
}
render方法中的onClick 事件监听函数中调用this.setState方法,可以设置this.state 中的属性
推荐使用箭头函数,避免this 造成困扰。
简单组件(函数组件)
简单组件是一个函数,不需要使用class关键字,当然就没有constructor和state
const Square = (props) => {
return (<button className= "square"
onClick= { props.onClick} >{ props.value }
</button>)
}
受控组件
input、<select>、<textarea> 等表单的状态发生改变,都得同时通过onChange事件改变组件中的state值,否则表单不会发生变化。通过这种方式控制取值的表单叫做受控组件。
class Input extends Component {
constructor(props){
super(props)
this.state = {
value:'3s'
}
}
render (){
return <input type="text" value = {this.state.value} /> // 用户在表单中输入任何信息都是无效的
}
}
// 使用事件来改变
render (){
return (
<input
type="text"
value = {this.state.value}
onChange = {({target}) =>{
this.setState({
value:target.value
})
}}
/>
)
}
React受控组件更新state的流程:
- 通过在初始化state中设置表单默认值;
- 每当表单值发生变化时,调用
onChange事件 - 事件通过合成的事件对象来改变状态更新
state - setState触发视图渲染更新,完成表单组件值的更新
渲染多个组件
将组件变成数组集合放入花括号中即可渲染多个组件,通常使用数组的map()方法
const Lis = (props) => {
const lis = props.list.map((val,key)=> <li key={key}>{key+1}</li>);
return <ul>{lis}</ul>
}
const list = Array(7).fill(null);
ReactDOM.render(
<Lis list = {list} />,
document.getElementById('root')
);
状态提升
当多个组件发生数据联动时,建议将共享状态提升到最近的共同父组件中去。
/*
* @Author: Owen
* @Date: 2019-07-23 23:55:17
* @Last Modified by: Owen
* @Last Modified time: 2019-07-29 16:06:22
*/
import React,{Component} from 'react';
import {render} from 'react-dom';
// 温度转化器
let toConvert = (temperature,callback) => {
let num = parseInt(temperature);
if(Number.isNaN(num)) return ''
num = callback(num)
return Math.round(num*1000)/1000;
}
const BoilingVerdict = (props) =>{
let text = props.temperature > 100?'':' not';
return (<p>
The water would{text} boil.
</p>)
}
// 公共input组件只接收行为和状态
const TemperatureInput = (props) =>{
return (
<input
value ={props.temperature}
onChange = {props.valueChange}
/>
)
}
// 父组件设置行为和状态
class Calculator extends Component {
constructor(props){
super(props)
this.state = {
temperature:'',
scale:'C'
}
}
toFahrenheit({target}) {
this.setState({
temperature:target.value,
scale:'F'
})
}
toCelsius({target}) {
this.setState({
temperature:target.value,
scale:'C'
})
}
render() {
let {temperature,scale} = this.state;
let celsius = scale === 'F'?toConvert(temperature,(val)=>(val - 32)*5/9):temperature;
let fahrenheit = scale === 'C'?toConvert(temperature,(val)=>val*9/5+32):temperature;
return (
<div>
<div>
Celsius:
<TemperatureInput
scale ='C'
temperature = {celsius}
valueChange = {this.toCelsius.bind(this)}
/>
</div>
<div>
Fahrenheit:
<TemperatureInput
scale ='F'
temperature = {fahrenheit}
valueChange = {this.toFahrenheit.bind(this)}
/>
</div>
<div><BoilingVerdict temperature = {this.state.temperature} /></div>
</div>
);
}
}
render(<Calculator />,document.querySelector('#root'))
在就React 应用中,任何科比数据应当只有一个相对应的数据源,通常,多个组件需要相同数据,可以将数据提升到这些组件的共同父组件中。依靠自上而下的数据流,去控制组件,而不是尝试在不同组件同步 state。这样会减少将来排查和隔离BUG所需要的工作量
组合(类似vue中的 slot)
有些组件无法提前知晓它们子组件的具体内容,需要留坑,那么也可以通过 props来占位。
默认坑位props.children
件起始标签和结束标签之间的内容都会被将{props.children}替换。
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
}
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
}
自定义坑位
因为 React元素 本质就是对象,所以可以将它当中参数像其他数据一样传递。
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}
JSX
每个 JSX 元素都是调用 React.createElement() 的语法糖。一般来说,如果你使用了 JSX,就不再需要调用
createElement()或createFactory()方法。
React 提出的一种叫 JSX 的语法,这应该是最开始接触 React 最不能接受的设定之一,因为前端被“表现和逻辑层分离”这种思想“洗脑”太久了。实际上组件的 HTML 是组成一个组件不可分割的一部分,能够将 HTML 封装起来才是组件的完全体.
JSX是一个JavaScript语法扩展。它类似于模板语言,但它具有JavaScript 的全部能力。它最终会被编译为
React.createElement()函数调用,返回称为React元素的普通JavaScript`对象。
推荐使用箭头函数,避免this 造成困扰
function Square(props) {
return (
< button className = "square"
onClick = { props.onClick } >
{ props.value }
</button>
);
}
class Board extends React.Component {
constructor(props){
super(props)
this.state = {
squares: Array(9).fill(null),
xIsNext:true, // 先落子,并确认该哪位玩家落子
}
}
/**
* 只接受一个squares副本,而不直接修改本身数据
* 1. 这样可以简化复杂的功能,不可变性使得复杂的特性更容易实现。
* 2. 可以跟踪数据的改变,如果直接修改源数据就很难跟踪变化的数据。
* 3. 可以帮助我们在 React 中创建 purecomponents。可以轻松的确定不可变数据是否发生了改变,
* 从而确定何时对组件进行重新渲染。
* @param {*} i
* @memberof Board
*/
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = this.state.xIsNext? "X":"O";
this.setState({ squares,xIsNext:!this.state.xIsNext })
}
renderSquare(i) { // 返回一个 Square 组件
return ( < Square
value = { this.state.squares[i] }// 给子组件传递 value数据
onClick = {()=> this.handleClick(i)} // 给子组件传递 onClick事件
/>);
}
render() {
let {state} = this;
const status = `Next player: ${state.xIsNext?'X':'O'}`;
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
}
在 JSX 中你可以任意使用JavaScript表达式,只需要用一个大括号({})括起来;
事实上每个 React 元素都是一个JavaScript 对象,可以把它保存在变量中或者作为参数传递。
为避免遇到自动插入分号陷阱,最好将内容包裹在小括号中,如果只有一行代码则不需要括号。
// 加括号
class App extends React.Component {
render() {
return (
<div className="shopping-list">
<h1>Shopping List for</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}
// 不用加括号
class App extends React.Component {
render() {
return <li>Instagram</li>;
}
}
JSX 语法更接近于 JavaScript,所以 ReactDom 使用cameCase(小驼峰命名)来定义属性名称,并且不要使用引号将大括号包裹,两者是不能并存的。对于字符串值使用引号,对于表达式使用大括号
React 中无法通过 return false 的方式阻止默认行为,必须使用e.preventDefault()阻止默认事件。但是不用担心event事件的兼容问题
JSX 本身就能防止XSS攻击
// 原生DOM
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
// JSX
class App extends React.Component {
render() {
return (
<a href="#" onclick={(e)=>this.handleClick(e)}> //每次渲染时都会创建不同的回调函数。该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染。
Click me
</a>;
<a href="#" onclick={(e)=>this.handleClick(id,e)}> // 向事件处理程序传递参数
Click me
</a>;
)
}
}
事件处理程序回调函数中的 this
- 在
JavaScript中,class的方法默认不会绑定this。如果你忘记绑定this.handleClick并把它传入了onClick,当你调用这个函数的时候this的值为undefined。
class App extends React.Component {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
// 注意: 这是 **实验性** 语法。 使用 Create React App 默认会启用此语法
handleClick = (e)=> {
e.preventDefault();
console.log(e)
}
render() {
return (
<a href="#" onclick={this.handleClick}>
Click me
</a>;
<a href="#" onclick={this.handleClick。bind(this,id)}> // 向事件处理程序传递参数, 事件对象会被隐式传递
Click me
</a>;
)
}
}
参考资料
react 官网
React 入门教程
React 基础笔记的更多相关文章
- React基础笔记
参考文章: http://www.ruanyifeng.com/blog/2015/03/react.html https://segmentfault.com/a/1190000002767365 ...
- React学习笔记(一) 基础知识
现在最热门的前端框架有AngularJS.React.Bootstrap等.自从接触了ReactJS,ReactJs的虚拟DOM(Virtual DOM)和组件化的开发深深的吸引了我. React的基 ...
- React学习笔记(五)State&声明周期
React学习笔记(五) 四.State&声明周期 可以为组件添加"状态(state)".状态与属性相似,但是状态是私有的,完全受控于当前组件. 局部状态就是只能用于类(定 ...
- React routerV4 笔记
React routerV4 笔记 一.基础路由示例 import React from 'react' import { BrowserRouter as Router, Route, Li ...
- 【React】react学习笔记02-面向组件编程
react学习笔记02-面向组件编程 面向组件编程,直白来说,就是定义组件,使用组件. 以下内容则简单介绍下组建的声明与使用,直接复制demo观测结果即可. 步骤: 1.定义组件 a.轻量组件-函 ...
- 【React】react学习笔记01-概念与基本使用
俺为啥要学这玩意: 家里的杂事好不容易处理完了,开始正式静下心来学习~博主是做后端开发的,js基础不深,之前也是用React写过许多东西了,但是基本上都是用的CV大法,别人的组 件修修改改拿来 ...
- react基础(1)
在 react入门系列 里面,介绍了一些react的基础知识,在react基础部分,会结合手脚架工具进行更多的总结. 关于webpack我在这里就不讲解了,有需要的小伙伴可以自己去百度一下学习资料,我 ...
- Java基础笔记 – Annotation注解的介绍和使用 自定义注解
Java基础笔记 – Annotation注解的介绍和使用 自定义注解 本文由arthinking发表于5年前 | Java基础 | 评论数 7 | 被围观 25,969 views+ 1.Anno ...
- php代码审计基础笔记
出处: 九零SEC连接:http://forum.90sec.org/forum.php?mod=viewthread&tid=8059 --------------------------- ...
随机推荐
- 华为云北京四业务,访问北京一OBS桶,配置指南
[摘要] 华为云跨数据中心,从北京四访问北京一的OBS桶里面的数据.免去数据迁移的麻烦 1 驱动力 跨region访问OBS桶里面的数据时.如果不走云连接,一个OBS桶域名对应的IP地址,是 ...
- 【并发技术16】线程同步工具Exchanger的使用
如果两个线程在运行过程中需要交换彼此的信息,比如一个数据或者使用的空间,就需要用到 Exchanger 这个类,Exchanger 为线程交换信息提供了非常方便的途径,它可以作为两个线程交换对象的同步 ...
- 宜信SDL实践:产品经理如何驱动产品安全建设
一.序言 本文从产品经理的角度出发,对产品经理的安全职责.产品驱动安全的内涵.工作内容.工作方法.所需安全资源.以及产品经理的安全工作量进行了分析.希望所有产品经理在没有心理负担的情况下,有目标.有方 ...
- Xcode中.a文件引起的错误
一. TARGETS -> Build Settings-> Search Paths下 1. Library Search Paths 删除不存在的路径,保留.a文件的路径(此 ...
- 香港6合彩数据分析 V1.0
最近写了个VBA小工具,分析香港6合彩中奖的概率,得出的结果不尽人意,但至少不会让你赔钱,嘿嘿! 点此链接获取 密码:3u65
- 2019CCPC秦皇岛 J MUV LUV EXTRA(KMP)
MUV LUV EXTRA Time Limit: 2000/1500 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)T ...
- 摄像头CMOS和CCD的比较
转载自网络,在此做一下总结,仅供参考: 1.CCD每曝光一次,在快门关闭后进行像素转移处理,将每一行中每一个像素(pixel)的电荷信号依序传入“缓冲器”中,由底端的线路引导输出至 CCD 旁的放大器 ...
- mongodb验证
mongodb默认是不需要用户名和密码就可以增删查改的.要设置成需要用户名和密码访问,步骤如下: 通过下面的命令启动mongodb服务器 mongod 启动之后再登录,执行下面命令: use test ...
- 正则去掉html标签之间的空格、换行符、tab符,但是保留html标签内部的属性空格
今天遇到一个比较少见的去空格: 正则去掉html标签之间的空格.换行符.tab符,但是保留html标签内部的属性空格 JS 举例: "<a href='baidu.com' name= ...
- .NetCore部署到CentOS
“天下熙熙,皆为利来:天下攘攘,皆为利往.”,越来越多的人涌入IT这个行业,使得技术发展日新月异之外,也会无情淘汰跟不上潮流的人,所以作为IT从业人员,一定要时刻关注前沿技术,免得有朝一日被拍在沙滩上 ...