1、项目基本搭建
create-react-app是react中最简单的创建单页面程序的方式。在使用它之前先保证你的机器上安装了Node环境
# 全局安装create-react-app
$ yarn global add create-react-app
# 创建项目
create-react-app react01
cd react01
yarn start
//浏览器localhost:3000/可以查看到开启的服务
2、JSX语法简介
简单的JSX语法
const element = <h1>Hello, world!</h1>;
它被称为 JSX, 一种 JavaScript 的语法扩展
在 JSX 中使用表达式
你可以任意地在 JSX 当中使用JavaScript 表达式在 JSX 当中的表达式要包含在大括号里
const str = "hello world" + "你好世界";
const element = (
<h1>
Hello, {str}
</h1>
);
JSX 本身其实也是一种表达式
在编译之后呢,JSX 其实会被转化为普通的 JavaScript 对象。
这也就意味着,你其实可以在 if 或者 for 语句里使用 JSX,将它赋值给变量,当作参数传入,作为返回值都可以
const renderJsx = () => {
let a = 10;
if(a > 5){
return <div>hello {a}</div>
}else{
return <div>hello world</div>
}
}
//=======调用renderJsx()即可
render(){
return(
<div>{renderJsx()}</div>
)
}
JSX 属性
//你可以使用引号来定义以字符串为值的属性
const element = <div tabIndex="0"></div>;
//===
//也可以使用大括号来定义以 JavaScript 表达式为值的属性
const element = <img src={user.avatarUrl} />;
切记你使用了大括号包裹的 JavaScript 表达式时就不要再到外面套引号了。JSX 会将引号当中的内容识别为字符串而不是表达式
JSX 嵌套(可以相互嵌套)
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
因为 JSX 的特性更接近 JavaScript 而不是 HTML , 所以 React DOM 使用 camelCase
小驼峰命名 来定义属性的名称,而不是使用 HTML 的属性名称。
例如,class
变成了 className
,而 tabindex
则对应着 tabIndex
JSX 防注入攻击
你可以放心地在 JSX 当中使用用户输入:
React DOM 在渲染之前默认会 [过滤]所有传入的值。它可以确保你的应用不会被注入攻击。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 [XSS(跨站脚本)]攻击。
const title = response.potentiallyMaliciousInput;
// 直接使用是安全的:
const element = <h1>{title}</h1>;
更多代码注入注意:https://zhuanlan.zhihu.com/p/28434174
3、组件&props
1、组件定义
js函数定义
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
2、你也可以使用ES6 class来定义一个组件:
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
//调用
<Welcome name="lily"/>
3、组件渲染
import React, { Component } from 'react';
import './App.css';
//====组件 Welcome
function Welcome(props) {
return <div>hello, {props.name}</div>
}
const element = <Welcome name={"lily"}/>;
class App extends Component {
render() {
return (
<div className="App">
{element}
</div>
);
}
}
export default App;
4、生命周期详解
1、state:传递及状态的改变
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
//通过事件值的改变
clickEvent(){
this.setState({
date: "2019-03-27"
})
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
2、生命周期
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
//当 `Clock` 组件第一次被渲染到 DOM 中的时候,就为其设置一个计时器这在 React 中被称为“挂载(mount)”。
//=====设置计时器:
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
//同时,当 DOM 中 `Clock` 组件被删除的时候,应该清除计时器这在 React 中被称为“卸载(umount)”。
//==清除计时器
clearInterval(this.timerID);
}
//定时器方法
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
3、正确地使用 State
不要直接修改 State,此代码不会重新渲染组件
// Wrong
this.state.comment = 'Hello';
//yes
//而是应该使用 setState():
this.setState({comment: 'Hello'});
4、State 的更新可能是异步的
出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。因为 this.props 和 this.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。
此代码可能会无法更新计数器:
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
要解决这个问题,可以让 setState() 接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
5、事件处理
1、事件命名:小驼峰式(camelCase)
6、条件渲染
与运算符 &&
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
);
}
const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
<Mailbox unreadMessages={messages} />,
document.getElementById('root')
);
三目运算符
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>
);
}
阻止组件渲染
在极少数情况下,你可能希望能隐藏组件,即使它已经被其他组件渲染。若要完成此操作,你可以让 render 方法直接返回 null,而不进行任何渲染
import React, { Component } from 'react';
function WarningBanner(props) {
if (!props.warn) {
return null;
}
return (
<div className="warning">
Warning!
</div>
);
}
class App extends Component {
render() {
return (
<div className="App">
<WarningBanner/>
</div>
);
}
}
export default App;
在组件的 render 方法中返回 null 并不会影响组件的生命周期。例如,上面这个示例中,componentDidUpdate 依然会被调用
7、列表keys
Keys 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识
一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串
当元素没有确定 id 的时候,万不得已你可以使用元素索引 index 作为 key
const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);
8、状态提升
通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去, 通过改变父级的状态统一改变子组件的状态