前言
React(有时叫React.js或ReactJS),是一个为数据提供渲染为HTML视图的开源JavaScript 库。React视图通常采用包含以自定义HTML标记规定的其他组件的组件渲染。React为程序员提供了一种子组件不能直接影响外层组件(”data flows down”)的模型,数据改变时对HTML文档的有效更新,和现代单页应用中组件之间干净的分离。(维基百科)
JSX文件
- JSX是JS的一种扩展语言,它的本质还是JS
- 通过babel编译器编译JSX文件
JSX文件的语法格式
1
| React.createElement("div", null, "hello");
|
引入编译器
- 引入babel编译器到html文件,实现自动编译jsx语法代码
1 2 3 4
| <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> <script type="text/babel"> let html = <div>hello</div>; </script>
|
手动编译JSX文件
项目初始化
下载脚手架
1
| npm install --save-dev @babel/core @babel/cli @babel/preset-react
|
创建一个babel配置文件
- 创建一个
babel.config.js
或者.babelrc
文件
babelrc1 2 3
| { "presets": ["@babel/preset-react"] }
|
使用脚手架
<input>
:编译之前的.jsx
文件
<output>
:编译之后的.js
文件
1
| npx babel <input>.jsx -o <output>.js
|
JSX表达式
- JSX本身也是表达式
- 无论在JSX内容还是属性还是JSX本身,它都可以使用JSX表达式
1 2 3
| let name = ""; let jsx = <div>{name}</div>; let jsx = <div name={name}></div>;
|
className
- JSX中不能使用
class
给元素添加类名,因为jsx本质上是js,在js中class
是关键字,所以需要用className
代替class
为元素添加类名
1
| let jsx = <div className="div"></div>;
|
自动展开数组
1 2 3 4 5 6 7
| let arrs = [ <div key="1">1</div>, <div key="2">2</div>, <div key="3">3</div> ] let jsx = <div>{arrs}</div> ReactDOM.render(jsx, document.getElementById("app"));
|
运算符
三目运算
1 2 3
| let bool = true; let jsx = <div>{bool?<div>hello</div>:null}</div>; ReactDOM.render(jsx, document.getElementById("app"));
|
且运算
1 2 3
| let bool = true; let jsx = <div>{bool&&<div>hello</div>}</div>; ReactDOM.render(jsx, document.getElementById("app"));
|
循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| let arrs = [ {id: 1, name: "zhangsan"}, {id: 2, name: "lisi"}, {id: 3, name: "wangwu"} ]; let jsx = <div> <ul> { arrs.map(function(p, index) { return <li key={index}>{p.name}</li> }) } </ul> </div>; ReactDOM.render(jsx, document.getElementById("app"));
|
事件
- 通过
on+事件名
,给组件添加事件
- 这种写法默认会传递事件对象作为参数
1 2 3 4 5
| function fn(event) { console.log("hello"); } let jsx = <button onClick={fn}>按钮</button>; ReactDOM.render(jsx, document.getElementById("app"));
|
传递自定义参数
通过箭头函数
- 可以使用箭头函数,传递一个自定义参数
- 此时第二个参数为事件对象
1 2 3 4 5
| function fn(e, event) { console.log(e); } let jsx = <button onClick={()=>{fn("hello")}}>按钮</button>; ReactDOM.render(jsx, document.getElementById("app"));
|
通过bind函数
- 也可以使用bind传递自定义参数。传递的自定义参数要在第二个参数上定义
1 2 3 4 5
| function fn(e) { console.log(e); } let jsx = <button onClick={fn.bind(null, "hello")}>按钮</button>; ReactDOM.render(jsx, document.getElementById("app"));
|
引入React
通过CDN引入
1 2
| <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
|
hello world
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <!doctype html> <html> <head> <meta charset="UTF-8"> <title>Document</title> <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> </head> <body>
<div id="app">
</div>
</body> <script type="text/babel">
let html1 = <div>hello world</div>; ReactDOM.render(html1, document.getElementById("app"));
</script> </html>
|
React函数
创建一个标签
- 也可以通过jsx代码直接创建一个组件
- 返回一个虚拟对象
第一个参数:标签名
第二个参数:标签属性
第三个参数:标签内容
1
| React.createElement("div", null, "hello");
|
为标签添加内容
第一个参数:内容
第二个参数:绑定的标签
1 2
| let html = <div>hello</div>; ReactDOM.render(html, document.getElementById("app"));
|
React中的组件
定义类组件
1 2 3 4 5 6
| class Person extends React.Component { render() { return <div>hello</div>; } } ReactDOM.render(<Person/>, document.getElementById("app"));
|
定义函数组件
1 2 3 4
| function Person() { return <div>hello</div>; } ReactDOM.render(<Person/>, document.getElementById("app"));
|
组件嵌套
- 组建当作标签使用时,如果使用双标签要有结束标签,如果使用单标签要有闭合标签
1 2 3 4 5 6 7 8 9 10 11
| class Son extends React.Component { render() { return <div><p>这是子组件</p></div> } } class Father extends React.Component { render() { return <div><p>这是父组件</p><Son></Son></div> } } ReactDOM.render(<Father/>, document.getElementById("app"));
|
在组件内调用数据
- 在调用组件时传递参数,可以使用props属性中的对应属性来传递参数
- 在组件内部的props是只读的,不可以修改
- 如果props的数据源被修改,那么组件内得到的数据也会被修改
类组件
1 2 3 4 5 6 7
| class Person extends React.Component { render() { console.log(this.props); return <div>hello {this.props.name}</div>; } } ReactDOM.render(<Person name="world"/>, document.getElementById("app"));
|
函数组件
1 2 3 4 5
| function Person(props) { console.log(props); return <div>hello {props.name}</div>; } ReactDOM.render(<Person name="world"/>, document.getElementById("app"));
|
设置props的初始值
类组建
- 通过定义defaultProps来定义props的初始值
1 2 3 4 5 6 7 8 9 10
| class Person extends React.Component { static defaultProps = { name: "world" }; render() { console.log(this.props); return <div>hello {this.props.name}</div>; } } ReactDOM.render(<Person/>, document.getElementById("app"));
|
函数组件
- 直接在组件中添加一个defaultProps属性,就可以初始化props值
1 2 3 4 5 6 7
| function Person(props) { return <div>hello {props.name}</div>; } Person.defaultProps = { name: "world" }; ReactDOM.render(<Person/>, document.getElementById("app"));
|
双标签内的子标签
- 通过调用props.children属性来调用双标签内的子标签
类组建
1 2 3 4 5 6
| class Person extends React.Component { render() { return <div>hello {this.props.children}</div>; } } ReactDOM.render(<Person><span>world</span></Person>, document.getElementById("app"));
|
函数标签
1 2 3 4
| function Person(props) { return <div>hello {props.children}</div>; } ReactDOM.render(<Person><span>world</span></Person>, document.getElementById("app"));
|
this绑定
- 当通过子组件的函数调用父组件的函数时,需要使用构造器constructor进行this绑定,把父组件的this绑定到子组件的this上,否则函数中的this都是undefined
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Child extends React.Component { constructor() { super(); this.click = this.click.bind(this); } click() { this.props.onCli(); } render() { return <div><button onClick={this.click}>按钮</button></div>; } } class Father extends React.Component { fn() { console.log("hello world"); } render() { return <div><Child onCli={this.fn}></Child></div>; } } ReactDOM.render(<Father/>, document.getElementById("app"));
|
组件的状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class App extends React.Component { constructor() { super(); this.state = { name: "hello world" } this.click = this.click.bind(this); } click(){ this.setState({ name: "hello" }); } render() { return <div>{this.state.name}<button onClick={this.click}>点击更改state</button></div>; } } ReactDOM.render(<App/>, document.getElementById("app"));
|
数据双向绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class App extends React.Component { constructor() { super(); this.state = { name: "hello world" } this.change = this.change.bind(this); } change(event){ this.setState({ name: event.target.value }); } render() { return <div>{this.state.name}<input type="text" value={this.state.name} onChange={this.change}/></div>; } } ReactDOM.render(<App/>, document.getElementById("app"));
|
组件生命周期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class App extends React.Component { constructor() { super(); this.state = { name: "hello world" } console.log("constructor()"); this.click = this.click.bind(this); } click() { this.setState({ name: "hello" }); } componentDidMount() { console.log("componentDidMount()") } componentDidUpdate() { console.log("componentDidUpdate()") } componentWillUnmount() { console.log("componentWillUnmount()"); } render() { console.log("render()"); return <div> <p>{this.state.name}</p> <button onClick={this.click}>更新组建</button> <button onClick={()=>{ReactDOM.unmountComponentAtNode(document.getElementById("app"))}}>卸载组件</button> </div> } } ReactDOM.render(<App/>, document.getElementById("app"));
|
完成
参考文献
哔哩哔哩——Python小清风