React简易上手指南
1.React介绍
💎 起源
React
是用于构建用户界面的JavaScript
库,起源于Facebook的内部项目,该公司对市场上所有 JavaScript MVC
框架都不满意,决定自行开发一套,用于架设Instagram的网站。于2013年5月开源。
对市场上所有 JavaScript MVC框架都不满,决定自行开发一套。
这不禁让我联想,断水流大师兄。😎
💎 官方文档
闲话休提,言归正传。
先来附上官方文档地址,传送门点击即可穿越:
🚀官网地址
💎 对比Vue
React
和Vue
相同的地方,都是虚拟的DOM和组件化
。
不同于Vue的双向数据绑定
,React采用的是单向数据流
。
💎 单向数据流
React 中的数据流是单向的,并顺着组件层级从上往下传递。
2.环境搭建和HelloWorld程序
- 通过
React.Component
创建一个组件HelloComponent
- 使用
React
最常用的方法,通过render
将模板转为html
语言 - 通过
ReactDOM
插入到指定的DOM
节点,譬如container
🎸 示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="container">
</div>
<!-- react 核心js -->
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<!-- react-dom 渲染dom的js -->
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
<script>
class HelloComponent extends React.Component {
render() {
return React.createElement('h1', null, 'Hello World');
}
}
ReactDOM.render(React.createElement(HelloComponent, null,), document.getElementById('container'))
</script>
</body>
</html>
😜 页面显示
👺 简要说明
代码中的 React.createElement
方法,有三个参数:
- 第一个参数是必填,传入的是
HTML标签名称
,譬如:ul, li
- 第二个参数是选填,表示的是属性,譬如:
className
- 第三个参数是选填, 子节点,譬如: 要显示的
文本内容
开发时,通常会使用 JSX
语法,其实它最终会转化成 React.createElement
去创建元素。
3.初始JSX语法
设想如下变量声明:
const element = <h1>Hello, world!</h1>;
这个有趣的标签语法,既不是字符串也不是 HTML。
它被称为 JSX
,是一个 JavaScript 的语法扩展
。
我们建议在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。
JSX 可能会使人联想到模板语言,好像HTML,但它具有 JavaScript 的全部功能。
JSX使用的是ES6的标准,如果浏览器不支持,就需要将JSX转成普通JavaScript。
在生产中,通常使用Babel 转换
,再提交到服务器。
写这个demo的时候,使用 browser.js
也就是babel核心库,在客户端转换。
譬如,可以通过如下地址,引入 browser.min.js
文件
https://unpkg.com/babel-standalone@6.15.0/babel.min.js
💊 将之前的代码,修改一下。
React.createElement('h1', null, 'Hello World');
//改为JSX的写法
<h1>Hello World</h1>
React.createElement(HelloComponent, null,)
//改为JSX的写法
<HelloComponent />
📃 完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="container">
</div>
<!-- react 核心js -->
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<!-- react-dom 渲染dom的js -->
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js" crossorigin></script>
<script type="text/babel">
class HelloComponent extends React.Component {
render() {
return <h1>Hello World</h1>
}
}
ReactDOM.render(<HelloComponent />, document.getElementById('container'))
</script>
</body>
</html>
🐶 页面显示
上面已经说到过,JSX
语法,其实它最终会转化成 React.createElement
去创建元素。
也就是说,可以JSX
将理解为React.createElement(component, props, ...children)
方法的语法糖
。
可以通过props
传递属性参数
class HelloComponent extends React.Component {
render() {
return <h1>Hello { this.props.name }</h1>
}
}
ReactDOM.render(<HelloComponent name="malena" />, document.getElementById('container'))
页面成功显示属性name的值:
🙈🙉🙊 Malena 很美
哎呀,写着写着,又跑题了。😹
正如 React
官网所说, JSX是 JavaScript 的语法扩展,它具有 JavaScript 的全部功能。
那么,当然可以在 JSX 里面写三元表达式,或者二元表达式。
但是,不支持 if 或 else 语法。
class HelloComponent extends React.Component {
render() {
return <h1>Hello { this.props.name ? this.props.name: 'World' }</h1>
}
}
ReactDOM.render(<HelloComponent />, document.getElementById('container'))
class HelloComponent extends React.Component {
render() {
return <h1>Hello { this.props.name || 'World' }</h1>
}
}
ReactDOM.render(<HelloComponent />, document.getElementById('container'))
4.进阶JSX语法
介绍一下 JSX
中循环的写法,其实和JavaScript一样。
let names = ['mila', 'malena', 'morgan'];
class HelloComponent extends React.Component {
render(h) {
return (
<div>
{
names.map(name => <div key={name}> Hello, {name}</div>)
}
</div>
)
}
}
ReactDOM.render(<HelloComponent />, document.getElementById('container'))
🍜 刚才是通过JavaScript的数组,循环遍历。也可以直接写JSX进行循环。
let arr = [
<h1>mila</h1>,
<h1>malena</h1>,
<h1>morgan</h1>
]
ReactDOM.render(<div>{ arr }</div>, document.getElementById('container'))
🍕 页面显示
需要注意的是,数组循环,一定要加上key
值。
否则,将会看到一个警告 a key should be provided for list items
意思是当你创建一个元素时,必须包括一个特殊的 key
属性。
🎯 key
key
帮助 React
识别哪些元素改变了,比如被添加或删除。
因此你应当给数组中的每一个元素赋予一个确定的标识。
关于 列表 & Key
的详情讲解,请移步官方文档:
5.组件state成员
React组件是React最重要的组成部分。
根据不同 state
状态,渲染不同组件。和Vue一样,都是数据驱动页面。
👒 代码示例:
class TextBoxComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
enable: false
}
}
// 注意,handleClick 方法要用箭头函数
// 因为,点击时,handleClick()方法中的this已经不是组件里的this
// 箭头函数,使得this从正常情况下的动态作用域(根据运行位置确定值)变成了静态作用域(根据定义位置确定值,也就是词法作用域)。
handleClick = (event) => {
this.setState({ enable: !this.state.enable })
}
render(h) {
return (
<p>
<input type="text" disabled={this.state.enable} />
<button onClick={this.handleClick}>改变TextBoxComponent状态</button>
</p>
)
}
}
ReactDOM.render(<TextBoxComponent />, document.getElementById("container"))
6.Props和Render
👕 props
举个例子,一个input
输入框,类型type,就是props
<input type="text" />
在 React
中使用 JSX
语法,可以使用类似 HTML的写法,通过属性传入参数。
class HelloBox extends React.Component {
render(h) {
return (
<div>{'Hello' + this.props.attr}</div>
)
}
}
ReactDOM.render(<HelloBox attr="Halo Beach" />, document.getElementById('container'))
🚤 render
render
是一个函数。
对组件来说,render在创建时,是必须的。
render
用于检测 this.state
和 this.props
,用于返回组件实例。
在render内,不应该改变组件的state,也不和浏览器交互。
state和交互,写在生命周期和其他函数里。
render里就是最简单的,最纯粹的,组件的主体。
7.组件的生命周期
组件的生命周期可分成三个状态:
Mounting
(挂载):已插入真实 DOMUpdating
(更新):正在被重新渲染Unmounting
(卸载):已移出真实 DOM
🎄 挂载
当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:
1.constructor
(): 在 React 组件挂载之前,会调用它的构造函数。
2.getDerivedStateFromProps
(): 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。
3.render
(): render() 方法是 class 组件中唯一必须实现的方法。
4.componentDidMount
(): 在组件挂载后(插入 DOM 树中)立即调用。
render
() 方法是 class 组件中唯一必须实现的方法,其他方法可以根据自己的需要来实现。
💃 更新
每当组件的 state
或 props
发生变化时,组件就会更新。
当组件的 props
或 state
发生变化时会触发更新。组件更新的生命周期调用顺序如下:
1.getDerivedStateFromProps
(): 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。根据 shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。
2.shouldComponentUpdate
():当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。
3.render
(): render() 方法是 class 组件中唯一必须实现的方法。
4.getSnapshotBeforeUpdate
(): 在最近一次渲染输出(提交到 DOM 节点)之前调用。
5.componentDidUpdate
(): 在更新后会被立即调用。
render
() 方法是 class 组件中唯一必须实现的方法,其他方法可以根据自己的需要来实现。
💘 卸载
当组件从 DOM 中移除时会调用如下方法:
1.componentWillUnmount
(): 在组件卸载及销毁之前直接调用。
😍 示例代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 实例</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {data: 0};
this.setNewNumber = this.setNewNumber.bind(this);
}
setNewNumber() {
this.setState({data: this.state.data + 1})
}
render() {
return (
<div>
<button onClick = {this.setNewNumber}>INCREMENT</button>
<Content myNumber = {this.state.data}></Content>
</div>
);
}
}
class Content extends React.Component {
componentWillMount() {
console.log('Component WILL MOUNT!')
}
componentDidMount() {
console.log('Component DID MOUNT!')
}
componentWillReceiveProps(newProps) {
console.log('Component WILL RECEIVE PROPS!')
}
shouldComponentUpdate(newProps, newState) {
return true;
}
componentWillUpdate(nextProps, nextState) {
console.log('Component WILL UPDATE!');
}
componentDidUpdate(prevProps, prevState) {
console.log('Component DID UPDATE!')
}
componentWillUnmount() {
console.log('Component WILL UNMOUNT!')
}
render() {
return (
<div>
<h3>{this.props.myNumber}</h3>
</div>
);
}
}
ReactDOM.render(
<div>
<Button />
</div>,
document.getElementById('example')
);
</script>
</body>
</html>
8.组件小实例
🍎 业务逻辑,在生命周期钩子函数里编写。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>组件</title>
</head>
<body>
<div id="container">
</div>
<!-- react 核心js -->
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<!-- react-dom 渲染dom的js -->
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js" crossorigin></script>
<script type="text/babel">
class HelloBox extends React.Component {
constructor(props) {
super(props)
this.state = {
opacity: 1.0
}
}
componentDidMount() {
setInterval(() => {
var opacity = this.state.opacity;
opacity -= .05;
if(opacity < 0.1)opacity = 1.0
this.setState({ opacity })
}, 100);
}
render() {
return (
<div style={{ opacity: this.state.opacity }}>
<h1>Malena Morgan {this.props.name}</h1>
</div>
)
}
}
ReactDOM.render(<HelloBox name="naughty girl" />, document.getElementById('container'))
</script>
</body>
</html>
🍌 页面显示
9.this.porps.children
this.porps
和组件属性是一一对应的。
this.porps.children
代表的是子节点。
通过 React.Children.map
() 方法,可以遍历子节点。
class NotesList extends React.Component {
render() {
return (
<ol>
{
React.Children.map(this.props.children, (child) => {
return (<li>{child}</li>)
})
}
</ol>
)
}
}
ReactDOM.render(
<NotesList>
<span>mila</span>
<span>malena</span>
<span>morgan</span>
<span>naughty girl</span>
</NotesList>,
document.getElementById('container'))
10.组件的属性验证
🏀 props属性验证
为了确保组件引入的属性有意义,React引入propTypes
机制。
React.PropTypes提供 validator 验证数据的有效性。
使用 PropTypes 进行类型检查,官网链接:
正如官网所说:
自 React v15.5 起,React.PropTypes 已移入另一个包中。请使用 prop-types 库 代替。
props属性验证,只在开发模式下起作用。生产模式下,不起作用,为了节省资源。
实际开发中,使用npm安装,这里做demo演示,直接引入
< script src =" https://unpkg.com/prop-types@15.6/prop-types.js " > </ script >
🐯 示例代码
class MyTitle extends React.Component {
render() {
return (
<h1>
{this.props.title}
</h1>
)
}
}
MyTitle.propTypes = {
title: PropTypes.string.isRequired
}
var data = '123';
ReactDOM.render(<MyTitle title={data} />, document.getElementById('container'))
🍊 默认 Prop 值
通过配置特定的 defaultProps
属性来定义 props
的默认值:
MyTitle.defaultProps = {
title: 'ABCD'
}
11.ref获取真实DOM节点
🏃 如下所示,通过 this.refs.myTextInput
获取到真实DOM节点。
class MyComponent extends React.Component {
handleClick = () => {
this.refs.myTextInput.focus()
}
render(h) {
return (
<div>
<input type="text" ref="myTextInput" />
<input type="button" value="Focus the text input" onClick={this.handleClick} />
</div>
)
}
}
ReactDOM.render(<MyComponent />, document.getElementById('container'))
12.表单bind复用
🔮 查看React
官网关于表单的说明:
react.docschina.org/docs/forms.…
不同于Vue的双向数据绑定,React采用的是单向数据流,*
需要绑定onChange事件,通过setState改变state状态。
<input type="text" name="username" id="username" onChange={this.handleChange.bind(this, 'username')} value={this.state.username} />
handleChange = (name, event) => {
var newState = {}
newState[name] = name == 'checked' ? event.target.checked : event.target.value
this.setState(newState)
console.log(newState);
}
⌚ 表单示例demo
class MyForm extends React.Component {
constructor(props) {
super(props)
this.state = {
username: '',
girl: 'mila',
checked: true
}
}
submitHandle = (e) => {
e.preventDefault();
var is = this.state.checked ? '是' : '不是'
var style = this.state.girl == 'mila' ? 'naughty' : 'sexy';
console.log(this.state.username + is + style);
}
handleChange = (name, event) => {
var newState = {}
newState[name] = name == 'checked' ? event.target.checked : event.target.value
this.setState(newState)
console.log(newState);
}
render(h) {
return (
<form onSubmit={this.submitHandle}>
<label htmlFor="username">输入姓名</label>
<input type="text" name="username" id="username" onChange={this.handleChange.bind(this, 'username')} value={this.state.username} />
<br />
<label htmlFor="checkbox">是或者否</label>
<input type="checkbox" name="checked" id="checkbox" onChange={this.handleChange.bind(this, 'checked')} checked={this.state.checked} />
<br />
<label htmlFor="checkbox">选择girl</label>
<select name="girl" onChange={this.handleChange.bind(this, 'girl')} value={this.state.girl}>
<option value="mila">mila</option>
<option value="malena">malena</option>
<option value="morgan">morgan</option>
</select>
<br />
<button type="submit">确定</button>
</form>
)
}
}
ReactDOM.render(<MyForm />, document.getElementById('container'))
13.表单name复用
👑 给每一个标签设置 name
,不通过 bind
绑定 onChange
事件,这种写法更加简化。
<input type="text" name="username" id="username" onChange={this.handleChange} value={this.state.username} />
修改 handleChange
方法
handleChange = (event) => {
var newState = {}
newState[event.target.name] = event.target.name == 'checked' ? event.target.checked : event.target.value
this.setState(newState)
console.log(newState);
}
14.表单的可控组件
在 HTML 中,表单元素(如 input
、 textarea
和 select
)通常自己维护 state,并根据用户输入进行更新。
而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。
我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
🙋 表单demo中,使用的就是可控组件
handleChange = (event) => {
this.setState({ value: event.target.value })
console.log(this.state.value);
}
render(h) {
return (
<input type="text" value={this.state.value} onChange={this.handleChange} />
)
}
15.表单的不可控组件
在大多数情况下,我们推荐使用 受控组件 来处理表单数据。在一个受控组件中,表单数据是由 React 组件来管理的。另一种替代方案是使用非受控组件,这时表单数据将交由 DOM 节点来处理。
要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以 使用 ref 来从 DOM 节点中获取表单数据。
写起来麻烦,不好复用。不推荐使用。
🐔 简单示例:
class MyForm extends React.Component {
handleChange = (event) => {
var inputValue = ReactDOM.findDOMNode(this.refs.input).value
console.log(inputValue);
}
render(h) {
return (
<input type="text" onChange={this.handleChange} defaultValue="mila" ref="input"/>
)
}
}
🎀 官网示例:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.input = React.createRef(); }
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value); event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} /> </label>
<input type="submit" value="Submit" />
</form>
);
}
}
那么,这次就先写到这儿了。🏄
下次再整理更新。敬请期待。📌
参考资料
🚀菜鸟教程
最后的话
以上,如果对你有用的话,不妨点赞👍收藏💖关注一下,谢谢 🙏
您的支持,就是对我最大的帮助 😊
转载自:https://juejin.cn/post/7132364515059957796