元素与组件
如果代码多了之后,不可能一直在render方法里写,所以就需要把里面的代码提出来,定义一个变量,像这样:
import React from 'react'
import ReactDOM from 'react-dom'
// 这里感觉又不习惯了?这是在用JSX定义一下react元素
const app = '<h1>欢迎进入React的世界</h1>'
ReactDOM.render(
app,
document.getElementById('root')
)
函数式组件( 无状态组件 PureComponent)
由于元素没有办法传递参数,所以我们就需要把之前定义的变量改为一个方法,让这个方法去return一个元素:
import React from 'react'
import ReactDOM from 'react-dom'
// 特别注意这里的写法,如果要在JSX里写js表达式(只能是表达式,不能流程控制),就需要加 {},包括注释也是一样,并且可以多层嵌套
const app = (props) => <h1>欢迎进入{props.name}的世界</h1>
ReactDOM.render(
app({
name: 'react'
}),
document.getElementById('root')
)
这里我们定义的方法实际上也是react定义组件的第一种方式-定义函数式组件,这也是无状态组件。但是这种写法不符合react的jsx的风格,更好的方式是使用以下方式进行改造
import React from 'react'
import ReactDOM from 'react-dom'
const App = (props) => <h1>欢迎进入{props.name}的世界</h1>
ReactDOM.render(
// React组件的调用方式
<App name="react" />,
document.getElementById('root')
)
这样一个完整的函数式组件就定义好了。但要注意!注意!注意!组件名必须大写,否则报错。
class组件
ES6的加入让JavaScript直接支持使用class来定义一个类,react的第二种创建组件的方式就是使用的类的继承,ES6 class
是目前官方推荐的使用方式,它使用了ES6标准语法来构建,看以下代码:
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
render () {
return (
// 注意这里得用this.props.name, 必须用this.props
<h1>欢迎进入{this.props.name}的世界</h1>
)
}
}
ReactDOM.render(
<App name="react" />,
document.getElementById('root')
)
运行结果和之前完全一样,因为JS里没有真正的class,这个class只是一个语法糖, 但二者的运行机制底层运行机制不一样。
-
函数式组件是直接调用, 在前面的代码里已经有看到
-
es6 class
组件其实就是一个构造器,每次使用组件都相当于在实例化组件,像这样:import React from 'react' import ReactDOM from 'react-dom' class App extends React.Component { render () { return ( <h1>欢迎进入{this.props.name}的世界</h1> ) } } const app = new App({ name: 'react' }).render() ReactDOM.render( app, document.getElementById('root') )
更老的一种方法
在16以前的版本还支持这样创建组件, 但现在的项目基本上不用
React.createClass({
render () {
return (
<div>{this.props.xxx}</div>
)
}
})
组件的组合、嵌套
将一个组件渲染到某一个节点里的时候,会将这个节点里原有内容覆盖
组件嵌套的方式就是将子组件写入到父组件的模板中去,且react没有Vue中的内容分发机制(slot),所以我们在一个组件的模板中只能看到父子关系
// 从 react 的包当中引入了 React 和 React.js 的组件父类 Component
// 还引入了一个React.js里的一种特殊的组件 Fragment
import React, { Component, Fragment } from 'react'
import ReactDOM from 'react-dom'
class Title extends Component {
render () {
return (
<h1>欢迎进入React的世界</h1>
)
}
}
class Content extends Component {
render () {
return (
<p>React.js是一个构建UI的库</p>
)
}
}
/** 由于每个React组件只能有一个根节点,所以要渲染多个组件的时候,需要在最外层包一个容器,如果使用div, 会生成多余的一层dom
class App extends Component {
render () {
return (
<div>
<Title />
<Content />
</div>
)
}
}
**/
// 如果不想生成多余的一层dom可以使用React提供的Fragment组件在最外层进行包裹
class App extends Component {
render () {
return (
<Fragment>
<Title />
<Content />
</Fragment>
)
}
}
ReactDOM.render(
<App/>,
document.getElementById('root')
)
#JSX 原理
要明白JSX的原理,需要先明白如何用 JavaScript 对象来表现一个 DOM 元素的结构?
看下面的DOM结构
<div class='app' id='appRoot'>
<h1 class='title'>欢迎进入React的世界</h1>
<p>
React.js 是一个帮助你构建页面 UI 的库
</p>
</div>
上面这个 HTML 所有的信息我们都可以用 JavaScript 对象来表示:
{
tag: 'div',
attrs: { className: 'app', id: 'appRoot'},
children: [
{
tag: 'h1',
attrs: { className: 'title' },
children: ['欢迎进入React的世界']
},
{
tag: 'p',
attrs: null,
children: ['React.js 是一个构建页面 UI 的库']
}
]
}
但是用 JavaScript 写起来太长了,结构看起来又不清晰,用 HTML 的方式写起来就方便很多了。
于是 React.js 就把 JavaScript 的语法扩展了一下,让 JavaScript 语言能够支持这种直接在 JavaScript 代码里面编写类似 HTML 标签结构的语法,这样写起来就方便很多了。编译的过程会把类似 HTML 的 JSX 结构转换成 JavaScript 的对象结构。
下面代码:
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
render () {
return (
<div className='app' id='appRoot'>
<h1 className='title'>欢迎进入React的世界</h1>
<p>
React.js 是一个构建页面 UI 的库
</p>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
编译之后将得到这样的代码:
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
render () {
return (
React.createElement(
"div",
{
className: 'app',
id: 'appRoot'
},
React.createElement(
"h1",
{ className: 'title' },
"欢迎进入React的世界"
),
React.createElement(
"p",
null,
"React.js 是一个构建页面 UI 的库"
)
)
)
}
}
ReactDOM.render(
React.createElement(App),
document.getElementById('root')
)
React.createElement
会构建一个 JavaScript 对象来描述你 HTML 结构的信息,包括标签名、属性、还有子元素等, 语法为
React.createElement(
type,
[props],
[...children]
)
所谓的 JSX 其实就是 JavaScript 对象,所以使用 React 和 JSX 的时候一定要经过编译的过程:
JSX —使用react构造组件,bable进行编译—> JavaScript对象 —
ReactDOM.render()
—>DOM元素 —>插入页面
#组件中DOM样式
一共有四种
- 行内样式
想给虚拟dom添加行内样式,需要使用表达式传入样式对象的方式来实现:
// 注意这里的两个括号,第一个表示我们在要JSX里插入JS了,第二个是对象的括号
<p style={{color:'red', fontSize:'14px'}}>Hello world</p>
行内样式需要写入一个样式对象,而这个样式对象的位置可以放在很多地方,例如render
函数里、组件原型上、外链js文件中
- 使用
class
React推荐我们使用行内样式,因为React觉得每一个组件都是一个独立的整体
其实我们大多数情况下还是大量的在为元素添加类名,但是需要注意的是,class
需要写成className
(因为毕竟是在写类js代码,会收到js规则的限制,而class
是关键字)
<p className="hello" style = {this.style}>Hello world</p>
- 不同的条件添加不同的样式
有时候需要根据不同的条件添加不同的样式,比如:完成状态,完成是绿色,未完成是红色。那么这种情况下,我们推荐使用classname/classnames这个包:
- css-in-js ( 在js中写css )
styled-components
是针对React写的一套css-in-js框架,简单来讲就是在js中写css。npm链接
styled-components是一个第三方包,要安装
#todoList
组件化开发React todolist, 项目开发中的组件的基本目录结构基本上是这样的:
/your-project
- src
- …
- components
- YourComponentOne
- index.js/YourComponentOne.js
- YourComponentTwo
- index.js/YourComponentTwo.js
- index.js 用于导出组件
注意:一个组件只干一件事情 ,所以TodoList和TodoItem要做成两个组件,这样也方便于后期理解shouldComponentUpdate
组件的数据挂载方式
React中数据分为两个部分
1. 属性
2. 状态
经验: 频繁变化的就写成状态
Vue中数据只有状态这一种类型