简介:React 是由 Facebook 创建和维护的开源视图库。 它是渲染现代 Web 应用程序用户界面(UI)的好工具。
一、JSX(JS 语法扩展)
React 使用名为 JSX 的 JavaScript 语法扩展,可以直接在 JavaScript 中编写 HTML。
这有几个好处。 可以在 HTML 中使用 JavaScript 的完整程序功能,并有助于保持代码的可读性。
在大多数情况下,JSX 类似于 HTML,但是涉及一些关键差异。
例如,因为 JSX 是 JavaScript 的语法扩展,所以实际上可以直接在 JSX 中编写 JavaScript。
要做到这一点,只需在花括号中包含希望被视为 JavaScript 的代码:{ ’this is treated as JavaScript code’ }(这被视为 JavaScript 代码)。
但是,由于浏览器不能解析 JSX,因此必须将 JSX 代码编译为 JavaScript。 在这个过程中,转换器 Babel 是一个很受欢迎的工具。
值得注意的是,底层调用 ReactDOM.render(JSX, document.getElementById(‘root’))。 这个函数调用将 JSX 置于 React 自己的轻量级 DOM 中。 然后,React 使用自己的 DOM 快照来实现增量更新。
const JSX = <h1>Hello JSX!</h1>;
const JSX = <div>
<h1>Heading.</h1>
<p>Paragraph</p>
<ul>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
</div>;
{/*<h1>Hanoi University of Science</h1>*/}
React 渲染 API
ReactDOM.render(ReactNode,document.getElementById('root'))
--> Babel转换器
--> JavaScript
--> Browser
HTML 属性和事件使用驼峰式写法
const JSX = (
<div className='myDiv'>
<h1>Add a class to this div</h1>
</div>
);
返回单个元素(即只有一个父元素包裹所有子元素)
在 JSX 中编写 JS 代码使用花括号:{ ... } 或 {*/ 注释 /*}
const JSX = (
<div>
{/* remove comment and change code below this line // Remember that comments in JSX have parentheses.
<h2>Welcome to React!</h2> <br > // ?
<p>Be sure to close all tags!</p>
<hr > // ?
remove comment and change code above this line */}{" "}
// Remember that comments in JSX have parentheses.
</div>
);
JSX 的所有标签都可以自闭合:<div/>
const JSX = (
<div>
</div>
);
//or
const JSX = (
<div/>
);
二、Component 组件(大写字母开头定义)
组件是 React 的核心。 React 中的所有内容都是一个组件。
有两种方法可以创建 React 组件。
第一种方法是使用 JavaScript 函数。 以这种方式定义组件会创建无状态功能组件(Hooks 组件可以有状态)。
要用函数创建组件,只需编写一个返回 JSX 或 null 的 JavaScript 函数。 需要注意的一点是,React 要求你的函数名以大写字母开头。
1. 无状态组件(Hook中称为函数组件)
function MyComponent(){
return(
<div>Completed challenge!</div> //记得返回JSX
);
}
2. class 组件 (ES6 语法糖)
class Kitten extends React.Component {
constructor(props) {
super(props); //super(props)作用是调用父类的构造函数React.Component
}
render() {//render(): 渲染JSX的方法
return (
<h1>Hi</h1>
);
}
}
3. 组合/嵌套组件
//将子组件放入父组件中
class Fruits extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h2>Fruits:</h2>
<NonCitrus />
<Citrus />
</div>
);
}
};
class TypesOfFood extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>Types of Food:</h1>
<Fruits />
<Vegetables />
</div>
);
}
};
三、props
1. 传递方式 – 单向数据流
在 React 中,可以将属性传递给子组件。单向数据流
function 组件
const CurrentDate = (props) => {
return (
<div>
<p>The current date is: {props.date}</p>
</div>
);
};
class Calendar extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>What date is it?</h3>
<CurrentDate date={Date()} />
</div>
);
}
};
class 组件
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<Welcome name="Jessica"/>
</div>
);
}
};
class Welcome extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<p>Hello, <strong>{this.props.name}</strong>!</p>
</div>
);
}
};
2. 默认 props
React 还有一个设置默认 props 的选项。
可以将默认 props 作为组件本身的属性分配给组件,React 会在必要时分配默认 prop。
如果没有显式的提供任何值,这允许指定 prop 值应该是什么。
const ShoppingCart = (props) => {
return (
<div>
<h1>Shopping Cart Component</h1>
</div>
)
};
ShoppingCart.defaultProps = {
items: 0
};
3. propTypes & PropTypes
React 提供了有用的类型检查特性,以验证组件是否接收了正确类型的 props。
例如,应用程序调用 API 来检索数据是否是数组,然后将数据作为 prop 传递给组件。
可以在组件上设置 propTypes,以要求数据的类型为 array。 当数据是任何其它类型时,都会抛出警告。
const Items = (props) => {
return <h1>Current Quantity of Items in Cart: {props.quantity}</h1>
};
Items.propTypes = {
quantity: PropTypes.number.isRequired //其中number为类型;isRequired为必须
};
Items.defaultProps = {
quantity: 0
};
class ShoppingCart extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Items />
}
};
四、state
React 中最重要的主题之一是 state。
state 包含应用程序需要了解的任何数据,这些数据可能会随时间而变化。
应用程序能够响应 state 的变更,并在必要时显示更新后的 UI。
React 为现代 Web 应用程序的状态管理提供了一个很好的解决方案。
可以在类组件的 constructor 上声明 state 属性来在 React 组件中创建 state, 它在创建时使用 state 初始化组件。
state 属性必须设置为 JavaScript object(对象)
1. 初始化状态this.state={}
class StatefulComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "Name"
}
}
render() {
return (
<div>
<h1>{this.state.name}</h1>
</div>
);
}
};
2. 设置状态this.setState()
React 要求永远不要直接修改 state,而是在 state 发生改变时始终使用 this.setState()。
此外,应该注意,React 可以批量处理多个 state 更新以提高性能。
这意味着通过 setState 方法进行的 state 更新可以是异步的。
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'Initial State'
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
name: 'React Rocks!'
});
}
render() {
return (
<div>
<button onClick={this.handleClick}>Click Me</button>
<h1>{this.state.name}</h1>
</div>
);
}
};
3. 使用 state 切换元素
有时可能在更新状态的时候想知道上一个状态是什么。
但是状态更新是异步的,这意味着 React 可能会把多个 setState() 集中在一起批量更新。
所以计算下一个值时 this.state 或者 this.props 不能作为当前值。
正确的做法是,给 setState 传入一个函数,这个函数可以访问 state 和 props。 给 setState 传入函数可以保证 state 和 props 是正确的值。
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
visibility: false
};
this.toggleVisibility = this.toggleVisibility.bind(this);
}
toggleVisibility() {
this.setState(state => {
if (state.visibility === true) {
return { visibility: false };
} else {
return { visibility: true };
}
});
}
render() {
if (this.state.visibility) {
return (
<div>
<button onClick={this.toggleVisibility}>Click Me</button>
<h1>Now you see me!</h1>
</div>
);
} else {
return (
<div>
<button onClick={this.toggleVisibility}>Click Me</button>
</div>
);
}
}
}
五、将 this 绑定到 class 方法上
为组件类定义方法。 类方法通常需要使用 this 关键字,以便它可以访问方法中类的属性(例如 state 和 props)。 有几种方法可以让类方法访问 this。
一种常见的方法是在构造函数中显式地绑定 this,这样当组件初始化时,this 就会绑定到类方法。
在构造函数中的 handleClick 方法使用了 this.handleClick = this.handleClick.bind(this)。 然后,当在类方法中调用像 this.setState() 这样的函数时,this 指的是这个类,而不是 undefined。
注意: this 关键字是 JavaScript 中最令人困惑的方面之一,但它在 React 中扮演着重要的角色。
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
text: "Hello"
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
text: "You clicked!"
});
}
render() {
return (
<div>
<button onClick={this.handleClick}>Click Me</button>
<h1>{this.state.text}</h1>
</div>
);
}
};
六、将 state 作为 props 传递给子组件(重要)
有状态组件中包含对应用程序很重要的 state,然后用它渲染子组件。 如果想让这些组件能够访问该 state 的某些部分,就把这些部分作为 props 传入。
这个模式说明了 React 中的一些重要范例。
第一个是单向数据流, state 沿着应用程序组件树的一个方向流动,从有状态父组件到子组件, 子组件只接收它们需要的 state 数据。
第二,复杂的有状态应用程序可以分解成几个,或者可能是一个单一的有状态组件。 其余组件只是从父组件简单的接收 state 作为 props,并从该 state 渲染 UI。
它开始创建一种分离,在这种分离中,state 管理在代码的一部分中处理,而 UI 渲染在另一部分中处理。 将 state 逻辑与 UI 逻辑分离是 React 的关键原则之一。
当它被正确使用时,它使得复杂的、有状态的应用程序的设计变得更容易管理。
class MyApp extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: ''
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
inputValue: event.target.value
});
}
render() {
return (
<div>
<GetInput
input={this.state.inputValue}
handleChange={this.handleChange}/>
<RenderInput
input={this.state.inputValue}/>
</div>
);
}
};
class GetInput extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>Get Input:</h3>
<input
value={this.props.input}
onChange={this.props.handleChange}/>
</div>
);
}
};
class RenderInput extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>Input Render:</h3>
<p>{this.props.input}</p>
</div>
);
}
};
七、生命周期方法/钩子
React 组件有几种特殊方法,可以在组件生命周期的特定点执行操作。 这些称为生命周期方法或生命周期钩子,允许在特定时间点捕获组件。
这可以在渲染之前、更新之前、接收 props 之前、卸载之前等等。
以下是一些主要生命周期方法的列表:
componentWillMount() 渲染之前
componentDidMount() 接收 props 之前
shouldComponentUpdate() 更新之前
componentDidUpdate() 更新之后
componentWillUnmount() 卸载之前
1. componentWillMount
当组件被挂载到 DOM 时,componentWillMount() 方法在 render() 方法之前被调用。
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
componentWillMount() {
console.log('Component being mounted');
}
render() {
return <div />
}
};
2. componentDidMount
React 的最佳实践是在生命周期方法 componentDidMount() 中对服务器进行 API 调用或任何其它调用。
将组件装载到 DOM 后会调用此方法。 此处对 setState() 的任何调用都将触发组件的重新渲染。
在此方法中调用 API 并用 API 返回的数据设置 state 时,一旦收到数据,它将自动触发更新。
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
activeUsers: null
};
}
componentDidMount() {
setTimeout(() => {
this.setState({
activeUsers: 1273
});
}, 2500);
}
render() {
return (
<div>
<h1>Active Users: {this.state.activeUsers}</h1>
</div>
);
}
}
3. 添加事件侦听器
componentDidMount() 方法是添加特定功能所需的任何事件监听器的最佳位置。
React 提供了一个合成事件系统,它封装了浏览器中的事件系统。 这意味着,不管用户用的是什么浏览器,合成事件系统的行为都完全相同 – 即使不同浏览器之间的本地事件的行为可能不同。
之前已经接触了一些合成事件处理程序,如 onClick()。 React 的合成事件系统非常适合用于在 DOM 元素上管理的大多数交互。 但是,如果要将事件处理程序附加到 document 或 window 对象,则必须直接执行此操作。
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
message: ''
};
this.handleEnter = this.handleEnter.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
}
componentDidMount() {
document.addEventListener("keydown", this.handleKeyPress);
}
componentWillUnmount() {
document.removeEventListener("keydown", this.handleKeyPress);
}
handleEnter() {
this.setState((state) => ({
message: state.message + 'You pressed the enter key! '
}));
}
handleKeyPress(event) {
if (event.keyCode === 13) {
this.handleEnter();
}
}
render() {
return (
<div>
<h1>{this.state.message}</h1>
</div>
);
}
};
4. 使用 shouldComponentUpdate 优化重新渲染
当子组件接收到新的 state 或 props 时,可以调用该方法,并特别声明组件是否应该更新。
它将 nextProps 和 nextState 作为参数。
这种方法是优化性能的有效方法。 例如,默认行为是,当组件接收到新的 props 时,即使 props 没有改变,它也会重新渲染。
可以通过使用 shouldComponentUpdate() 比较 props 来防止这种情况发生。
该方法必须返回一个 boolean(布尔值),该值告诉 React 是否更新组件。 可以比较当前的 props(this.props)和下一个 props(nextProps),以确定你是否需要更新,并相应地返回 true 或 false。
class OnlyEvens extends React.Component {
constructor(props) {
super(props);
}
shouldComponentUpdate(nextProps, nextState) {
console.log('Should I update?');
if (nextProps.value % 2 == 0) {
return true;
}
return false;
}
componentDidUpdate() {
console.log('Component re-rendered.');
}
render() {
return <h1>{this.props.value}</h1>;
}
}
class Controller extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 0
};
this.addValue = this.addValue.bind(this);
}
addValue() {
this.setState(state => ({
value: state.value + 1
}));
}
render() {
return (
<div>
<button onClick={this.addValue}>Add</button>
<OnlyEvens value={this.state.value} />
</div>
);
}
}
八、CSS 样式(驼峰写法)
1. 内联样式
class Colorful extends React.Component {
render() {
return (
<div style={{ color: 'red', fontSize: '72'}}>
Big Red
</div>
);
}
};
2. 常量引用
const styles = {
color: 'purple',
fontSize: 40,
border: "2px solid purple",
};
class Colorful extends React.Component {
render() {
return (
<div style={styles}>Style Me!</div>
);
}
};
九、按条件渲染组件
1. if…else..
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
display: true
}
this.toggleDisplay = this.toggleDisplay.bind(this);
}
toggleDisplay() {
this.setState((state) => ({
display: !state.display
}));
}
render() {
if (this.state.display) {
return (
<div>
<button onClick={this.toggleDisplay}>Toggle Display</button>
<h1>Displayed!</h1>
</div>
);
} else {
return (
<div>
<button onClick={this.toggleDisplay}>Toggle Display</button>
</div>
);
}
}
};
2. &&
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
display: true
}
this.toggleDisplay = this.toggleDisplay.bind(this);
}
toggleDisplay() {
this.setState(state => ({
display: !state.display
}));
}
render() {
return (
<div>
<button onClick={this.toggleDisplay}>Toggle Display</button>
{this.state.display && <h1>Displayed!</h1>}
</div>
);
}
};
3. 三元表达式
const inputStyle = {
width: 235,
margin: 5
}
class CheckUserAge extends React.Component {
constructor(props) {
super(props);
this.state = {
userAge: '',
input: ''
}
this.submit = this.submit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({
input: e.target.value,
userAge: ''
});
}
submit() {
this.setState(state => ({
userAge: state.input
}));
}
render() {
const buttonOne = <button onClick={this.submit}>Submit</button>;
const buttonTwo = <button>You May Enter</button>;
const buttonThree = <button>You Shall Not Pass</button>;
return (
<div>
<h3>Enter Your Age to Continue</h3>
<input
style={inputStyle}
type="number"
value={this.state.input}
onChange={this.handleChange} /><br />
{
this.state.userAge === ''
? buttonOne
: this.state.userAge >= 18
? buttonTwo
: buttonThree
}
</div>
);
}
};
4. 根据props有条件地渲染
class Results extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<h1>
{this.props.fiftyFifty ? "You Win!" : "You Lose!"}
</h1>
)
};
};
class GameOfChance extends React.Component {
constructor(props) {
super(props);
this.state = {
counter: 1
}
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
counter: this.state.counter + 1
});
}
render() {
const expression = Math.random() >= 0.5 ? true : false
return (
<div>
<button onClick={this.handleClick}>Play Again</button>
<Results fiftyFifty={expression} />
<p>{'Turn: ' + this.state.counter}</p>
</div>
);
}
};
5. 根据state有条件地渲染
class GateKeeper extends React.Component {
constructor(props) {
super(props);
this.state = {
input: ''
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({ input: event.target.value })
}
render() {
let inputStyle = {
border: '1px solid black'
};
if (this.state.input.length > 15) {
inputStyle.border = '3px solid red';
}
return (
<div>
<h3>Don't Type Too Much:</h3>
<input
type="text"
style={inputStyle}
value={this.state.input}
onChange={this.handleChange} />
</div>
);
}
};
十、Array.map()渲染数组
const frontEndFrameworks = [
'React',
'Angular',
'Ember',
'Knockout',
'Backbone',
'Vue'
];
function Frameworks() {
const renderFrameworks = frontEndFrameworks.map((item, index) =>
<li key={index}>{item}</li>
);
return (
<div>
<h1>Popular Front End JavaScript Frameworks</h1>
<ul>
{renderFrameworks}
</ul>
</div>
);
};
十一、Array.Filter() 动态过滤数组
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
users: [
{
username: 'Jeff',
online: true
},
{
username: 'Alan',
online: false
},
{
username: 'Mary',
online: true
},
{
username: 'Jim',
online: false
},
{
username: 'Sara',
online: true
},
{
username: 'Laura',
online: true
}
]
}
}
render() {
const usersOnline = this.state.users.filter(user => user.online === true);
const renderOnline = usersOnline.map(user => <li key={user.username}>{user.username}</li>);
return (
<div>
<h1>Current Online Users:</h1>
<ul>
{renderOnline}
</ul>
</div>
);
}
};
十二、用 renderToString 在服务器上渲染 React
有两个关键原因可以解释为什么服务器上的渲染可能会在真实世界的应用程序中使用。
首先,如果不这样做,当 React 应用程序最初加载到浏览器时,它将包含一个代码量很少的 HTML 文件和一大堆 JavaScript。
这对于搜索引擎来说可能不太理想,因为它们试图为网页内容生成索引,以便人们可以找到这个应用。
如果在服务器上渲染初始 HTML 标记并将其发送到客户端,则初始页面加载的内容包含搜索引擎可以抓取的所有页面标记。
其次,这创造了更快的初始页面加载体验,因为渲染的 HTML 代码量要比整个应用程序的 JavaScript 代码小。 React 仍然能够识别你的应用并在初始加载后进行管理。
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return <div/>
}
};
ReactDOMServer.renderToString(<App />);