一. 官方推荐使用的工具链
- 如果你是在学习react或者创建一个新的单页面应用,你应该使用
Create React App
- 如果你是在用node.js构建服务端渲染的网站,可以尝试
Next.js
- 如果你是在构建面向内容的静态网站,可以使用
Gatsby
Create React App
- 作用:它能配置你的生产环境,以便你能使用最新的JavaScript特性,提高开发体验,并为生产环境优化你的应用程序
- 条件:Node >= 8.10 && npm >= 5.6
npx create-react-app my-app
cd my-app
npm start
注意:
第一行的npx是npm 5.2+ 的附带的package运行工具
Next.js
- next.js是一个流行的、轻量级的框架
- 用于配合react打造静态化和服务端渲染应用
- 包括开箱即用的路由方案和样式
- 假定你使用node.js作为服务器环境
Gatsby
- Gatsby是react创建静态网站的最佳方式
- 它让你能使用react的组件,但输出预渲染的html和css以保证最快的加载速度。
二. Hello World
ReactDom.render(
<h1>Hello World!</h1>,
document.querySelector('#id')
)
提示:
当然你也可以选择使用document.getElementById('id')
来获取元素
三. JSX
3.1 防止注入攻击
React Dom在渲染所有输入内容之前,都会默认进行转义。这样可以有效防止XSS(cross-site-scripting,跨站脚本)攻击。
3.2 在JSX中嵌入表达式
const name = 'Amy'
const vDom = <h1>hello {name}</h1>
ReactDom.render(
vDom,
document.querySelector('#id')
)
3.3 JSX也是一个表达式
function getGreeting(user) {
if (user) {
return <h1>hello {formatName(user)}</h1>
} else {
return <h1>hello world</h1>
}
}
3.4 JSX特定属性
例如:tabIndex
、 className
因为JSX更接近的语法是JavaScript而不是HTML,所以ReactDom使用小驼峰命名来定义属性的名称
四. 元素渲染
React只更新它需要更新的部分
React Dom 会将元素和它的子元素和它们之前的状态进行比较,并只会进行必要的更新来使DOM达到预期的状态
五. 组件 && props
<font color="gray">组件允许你把代码分成若干个独立可复用的代码片段,并对每个片段进行独立的构思</font>
5.1 函数组件 && class组件
定义组件最简单的方式就是定义JavaScript函数:
function Welcome(props) {
return <h1>Welcome,{props.name}</h1>
}
怎么判断一个函数是不是react组件:
- 有没有接受props属性
- 有没有返回一个react元素
他们被称为函数组件,因为他们的本质就是JavaScript函数
用es6的class来定义组件:
class Welcome extends React.Component {
return <h1>hello,{this.props.name}</h1>
}
5.2 渲染组件
function Welcome(props) {
return <h1>hello,{props.name}</h1>
}
const vDom = <Welcome name="Amy" />
ReactDom.render(
vDom,
document.querySelector('#id')
)
注意:组件名称必须以大写字母开头
React会将以小写字母为开头的组件视为原生dom标签。
5.3 组合组件
例如:我们可以创建一个多次渲染Welcome组件的App组件
function Welcome(props) {
return <h1>hello,{props.name}</h1>
}
function App() {
return (
<div id="App">
<Welcome name="Jony" />
<Welcome name="Amy" />
<Welcome name="Tom" />
</div>
)
}
ReactDom.render(
<App />,
document.querySelector('#id')
)
5.4 提取组件
将组件拆分为更小的组件
有这样一个Comment组件:
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
)
}
首先提取Avatar组件
function Avatar(props) {
return <img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name} />
}
现在针对Comment组件做一些微小的调整
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<Avatar user={props.author} />
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
)
}
接下来提取UserInfo组件
function UserInfo(props) {
return (
<div className="UserInfo">
<Avatar user={props.user} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
)
}
调整Comment组件
function Comment(props) {
return (
<div className="Comment">
<UserInfo user={props.author} />
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
)
}
5.5 props的只读性
所有React组件都必须像纯函数一样保护它的props不被修改
六. State && 生命周期
6.1 将函数组件转化成class组件
- 创建一个同名的es6 class,并继承于React.Compoment
- 创建一个空的render方法
- 将函数体移到render方法内
- 将render()内的props.*改为this.props.*
- 删除剩余的空函数声明
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
)
}
}
6.2 向class组件中添加局部的state
class Clock extends React.Component {
constructor(props) {
super(props)
this.state = {
date: new Date()
}
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
)
}
}
ReactDom.render(
<Clock />,
document.querySelector('#id')
)
6.3 将生命周期方法添加到class中
class Clock extends React.Component {
constructor(props) {
super(props)
this.state = {
date: new Date()
}
}
componentDidMount() {
this.timeId = setInterval(() => {
this.tick()
}, 1000)
}
componentWillUnmount() {
clearInterval(this.timeId)
}
tick() {
this.setState({
date: new Date()
})
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
)
}
}
ReactDom.render(
<Clock />,
document.querySelector('#id')
)
6.4 正确地使用State
6.4.1 不要直接修改State
6.4.2 State的更新有可能是异步的
出于性能考虑,React可能会把多个setState()合并成一个setState()调用
例如:下面的代码有可能会无法更新计数器:
this.setState({
counter: this.state.counter + this.props.increment
})
要解决这个问题,可以让setState()接收一个函数而不是一个对象,这个函数用上一个state作为第一个参数,将此次更新被应用的props作为第二个参数:
this.setState((state, props) => {
counter: state.counter + props.increment
})