Regex
React
[^2018 jul 5]:
初始化项目可以通过一个叫做create-react-app的包来创建
npm i -g create-react-app
create-react-app my-app
cd my-app
yarn start
在jsx代码中使用表达式
let a = 1;
let b = 3;
ReactDOM.render(
<div>
{a + b} //也可以使用模板字符串
//{ `${a} ${b}`}
</div>,
document.getElementById("root")
);
在花括号中可以进行简单的运算,调用有正确返回值的函数,插入模板字符串等等
for循环,流程判断语句都不属于表达式,所以不能在这里使用,如果需要进行判断,可以使用三目运算符,或者逻辑运算符进行判断
花括号可以在jsx文件的任意位置使用,代码结构也可以被当做变量,但要注意的是,插入的变量也必须要有一个根元素,否则将会报错
let jsx1 =(
<div>
<h1>yoooo</h1>
</div>
)
ReactDOM.render(
<div>
<p>
{jsx1}
</p>
</div>
,
document.getElementById("root")
);
并且,jsx的模板变量不能插入到模板字符串中
如果并不想插入的结构或者声明的变量中有一个根元素,可以使用react提出的解决方案,Fragment,他可以当做一个标签使用,但是他并不会被渲染出来,使用之前需要引入这个变量
import React ,{Fragment}from "react";
import ReactDOM from "react-dom";
let jsx1 =(
<Fragment>
<h1>yoooo</h1>
<h1>yoooo</h1>
</Fragment>
)
ReactDOM.render(
<Fragment>
{jsx1}
</Fragment>
,
document.getElementById("root")
);
样式
如果想要在jsx的代码中应用行间样式,需要使用双层的花括号
ReactDOM.render(
<Fragment>
<div style=>yooo</div>
</Fragment>
,
document.getElementById("root")
);
在jsx中样式不能有破折线,应该采用驼峰命名的形式
并且react会自动判断单位并补齐,所以在书写的时候并不一定要写全
关键字例如class需要改写成className
如果需要引用外部样式表,可以在js文件中使用es6的import命令来引入,create-react-app所搭建的环境会帮助我们进行编译
import './main.css'
组件
let People = ()=>(
<div>hhhhhhh
</div>
);
//es5 写法
function People(){
return(
<div>hhhhhhh
</div>
)
}
ReactDOM.render(
<Fragment>
<h1 className="kkk">yoooo</h1>
<People/>
</Fragment>
,
document.getElementById("root")
);
标签如果没有内容可以直接闭合
以上是生成一个自定义的组件的形式,函数必须要有正确的返回值,上面使用的es6的箭头函数默认返回的一个组件,有一点需要注意,react会把第一个字母大写的标签识别为组件,否则将被直接渲染到页面里
class Com extends React.Component{
render(){
return(
<div>
qqqqq
</div>
)
}
}
ReactDOM.render(
<Fragment>
<h1 className="kkk">yoooo</h1>
<Com/>
</Fragment>
,
document.getElementById("root")
);
组件也可以通过类的方式定义,类必须要继承自React.Component,且至少执行一个render方法,里面要有正确的返回结构,使用方式与声明函数相同,也可以在文件初始化的时候取出Component这个类
import React ,{Fragment,Component}from "react";
import ReactDOM from "react-dom";
class Com extends Component{
render(){
return(
<div>
qqqqq
</div>
)
}
}
Props
Props可以实现组件间的通信
属性的名和值都是任意的,组件所传递的属性和值会被props捕获到,并整体封装成一个对象,如果需要在组件中使用所传递的属性的值,可以使用props.###,如果什么都没有传递,那么props将会是一个空对象
####函数组件的通信
let Sunction = (props)=>{
return(
<p>This is Sunction {props.name}</p>
)
}
ReactDOM.render(
<Fragment>
<Sunction name="Joe" age={21} self={true}/>
</Fragment>
,
document.getElementById("root")
);
Class组件的通信
class Man extends Component{
render(){
let {name,age} = this.props;
return(
<div>
引入成功
name:{name},
age:{age}
</div>
)
}
}
ReactDOM.render(
<Fragment>
<Man name="joe" age={20}/>
</Fragment>
,
document.getElementById("root")
);
类组件的实例数据会被存储在实例的this.props下
React中为单向数据流,即从顶层流到底层
class Man extends Component{
render(){
let {name} = this.props;
return(
<div>
name:{name}
</div>
)
}
}//子组件
let Sunction = (props)=>{
return(
<p>
<Man name={props.test}/>
</p>
)
}//父组件
ReactDOM.render(
<Fragment>
<Sunction test="chuandi"/>
</Fragment>
,
document.getElementById("root")
);
组件所定义的标签之间的内容是默认为props.children,所以组件中没有使用到这个属性,那么是不会有任何显示的
let Sunction = (props)=>{
return(
<p>
{props.children}
</p>
)
}
ReactDOM.render(
<Fragment>
<Sunction>
this is children
</Sunction>
</Fragment>
,
document.getElementById("root")
);
DefaultProps
let Sunction = (props)=>{
return(
<p>
name:{props.name}
age:{props.age}
random:{props.renderprop()}
</p>
)
}
Sunction.defaultProps = {
name:'空',
age:0,
renderprop:()=>{}
}
ReactDOM.render(
<Fragment>
<Sunction renderprop={()=>Math.random()}/>
<Sunction name="Joe" age="20"/>
</Fragment>
,
document.getElementById("root")
);
defaultProps可以指定属性的默认值,如果属性没有被传递值或者传递的值等于undefined,那么默认值将会生效,否则正常渲染
在上面的例子中,如果没有默认的值,那么第二个Sunction组件在尝试调用props.renderprop()的时候,将会抛出错误,因为这个函数并没有被定义,所以在一些情况下,设置默认值是有必要的
Props-Type
PropTypes
输出了一系列的验证器,可以用来确保接收到的参数是有效的。例如,我们可以使用PropTypes.string
语句。当给 prop 传递了一个不正确的值时,JavaScript控制台将会显示一条警告。出于性能的原因,propTypes
仅在开发模式中检测。
他不会使页面崩溃掉,只会在控制台输出错误
import PT from 'prop-types'
Sunction.PT = {
// 你可以声明一个 prop 是一个特定的 JS 原始类型。
// 默认情况下,这些都是可选的。
optionalArray: PT.array,
optionalBool: PT.bool,
optionalFunc: PT.func,
optionalNumber: PT.number,
optionalObject: PT.object,
optionalString: PT.string,
optionalSymbol: PT.symbol,
// 任何东西都可以被渲染:numbers, strings, elements,或者是包含这些类型的数组(或者是片段)。
optionalNode: PropTypes.node,
// 一个 React 元素。
optionalElement: PropTypes.element,
//声明此项为必填项
age: PropTypes.number.isRequired
}
在react中组件属性的值如果是一个数组,那么会被默认展开并渲染到页面
State
State是私有的,完全受控于当前组件
只有类组件才拥有局部状态,所以如果一个函数组件需要局部状态,那么需要把他转换为类组件
class Magic extends Component {
constructor() {
super();
this.state = {
number: Math.random(),
name: "Joe"
};
}
render() {
let { number, name } = this.state;
return (
<div>
<h2>{name}</h2>
<p>{Math.random()}</p>
<button
onClick={() => {
this.setState({
number: Math.random()
});
}}
>
change number
</button>
</div>
);
}
}
ReactDOM.render(
<Fragment>
<Magic />
</Fragment>,
document.getElementById("root")
);
this.setState
在react中像下面这样直接调用this.state是不会重新渲染组件的,但是数据会发生改变
class Magic extends Component{
constructor(){
super()
this.state = {
number:Math.random()
}
}
render(){
let{number} = this.state;
return(
<div>
<button onClick={()=>{
this.state.number = Math.random()
console.log(this.state.number)
}}>click</button>
</div>
)
}
}
如果需要改变数据并渲染到视图,需要调用this.setState这个组件
他会再次调用render方法,并且重新读取数据
合并更新
react为了提高性能,当在一个组件中多次调用setState组件时,react会默认将其合并更新,也就是无论写了多少个setState组件,render方法都会合并为一次重新调用
<button onClick={()=>{
this.setState = {
number:Math.random()
}
this.setState = {
name:'Leo'
}
}}>click</button>
异步更新
新数据并不会被及时的捕获
this.props
和 this.state
可能是异步更新的,你不应该依靠它们的值来计算下一个状态
<button onClick={()=>{
let num = Math.random()
this.setState = {
number:num
}
console.log(this.state.number,num) // 当前值,上一次的值
}}>click</button>
要修复它,请使用第二种形式的 setState()
来接受一个函数而不是一个对象。 该函数将接收先前的状态作为第一个参数,将此次更新被应用时的props做为第二个参数
this.setState((prevState, props) => ({
console.log(prevState) // 数据被更新后的结果
console.log(props) //组件所传递的props
}));
SyntheticEvent
boolean bubbles //如果是事件是起泡事件,返回true
boolean cancelable //返回一个布尔值,表明该事件是否可以被取消,是返回true
DOMEventTarget currentTarget //指向事件处理程序附加到的元素
boolean defaultPrevented //表明事件的默认行为是否被取消,也就是是否执行了event.preventDefault()
number eventPhase //返回一个代表当前执行阶段的整数值
boolean isTrusted //返回一个布尔值,为true表明当前事件是由用户行为触发,否则表明事件由一个脚本生成的
DOMEvent nativeEvent //触摸事件相关
void preventDefault() //阻止默认行为
boolean isDefaultPrevented() //
void stopPropagation() //阻止事件的冒泡
boolean isPropagationStopped() //
DOMEventTarget target //指向事件的触发元素
number timeStamp //用于指定创建事件的时间(相对于纪元的毫秒数)
string type //返回事件类型
this指向
因为在react中结构并不是真正的dom,所以一些涉及this的问题需要进行处理
class Magic extends Component {
constructor(props) {
super(props)
this.state = {
name: 'Leo'
}
}
render() {
return (
<div>
<button onClick={()=>{
this.setState({
number: '666'
})}}>Change Number</button>
</div>
)
}
}
es6的箭头函数默认this指向函数所在的上下文,但如果使用原生的函数或者绑定类中的函数this就会指向undefined,这个时候需要用bind进行this的手动绑定
class Magic extends Component {
constructor(props) {
super(props)
this.state = {
name: 'Leo'
}
}
render() {
return (
<div>
<button onClick={(function(){
this.setState({
number: '666'
})
}
).bind(this)}>Change Number</button>
</div>
)
}
}
class Magic extends Component {
constructor(props) {
super(props)
this.state = {
name: 'Leo'
}
}
bundleclick(){
this.setState({
number: '666'
})
}
render() {
return (
<div>
<button onClick={this.bundleclick.bind(this)}>Change Number</button>
</div>
)
}
}
但是需要注意的是,上面的例子在每次触发点击事件后都会重新的进行this的绑定,相当于每次点击都生成新的button,并且react检测到render函数体内的变化就会重新渲染界面,会对性能有一定的影响,所以更推荐在构造函数内就将要执行的函数进行this的绑定,这样只会在实例化的时候进行一次绑定
class Magic extends Component {
constructor(props) {
super(props)
this.state = {
name: 'Leo'
}
this.bundleclick = this.bundleclick.bind(this)
}
bundleclick(){
this.setState({
number: '666'
})
}
render() {
return (
<div>
<button onClick={this.bundleclick}>Change Number</button>
</div>
)
}
}
如果事件很多的话,也可以使用es6的语法,但这种语法不在标准内,需要在开发环境内进行编译
class Magic extends Component {
constructor(props) {
super(props)
this.state = {
name: 'Leo'
}
}
bundleclick=()=>{
this.setState({
number: '666'
})
}
render() {
return (
<div>
<button onClick={this.bundleclick}>Change Number</button>
</div>
)
}
}