React
1.React核心概念
1.React 使用
单页面调试代码
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone"></script>
注意: 使用React语法需要将vscode中的js编译模式变成js-React模式
<script type="text/babel">
{/* 1. 使用实例 将h1内容插入id名为example的节点中 */}
ReactDOM.render(
<h1>React Example</h1>,
document.getElementById('React')
)
2.npm使用React语法
- 安装React语法并创建项目
$ cnpm install -g create-react-app
$ create-react-app my-app
$ cd my-app/
$ npm start
-
项目目录
my-app/ README.md node_modules/ package.json .gitignore public/ favicon.ico index.html manifest.json #指定了开始页面为index.html 是代码的源头 src/ App.css App.js App.test.js index.css index.js logo.svg
3.React元素渲染
元素是构成React应用的最小单位,用于描述屏幕上输出的内容
Ract中的元素事实上是普通的对象 ReactDOM可以确保浏览器DOM的数据内容与React中的元素相同
const Element = hello woorld!
4.更新元素渲染
React中的元素都是不可变的 当元素被创建之后 是无法改变内容和属性的
比如创建一个定时器 获取当地时间 结果获取到的时间都是相同的
6.JSX简介
- 语法简介
// jsx语法简介
// jsx语法中可以使用表达式 用{} 代替变量
const autor = '王万琦'
const element = <h1>这个人的姓名是{autor}</h1>
-
jsx防止注入攻击
-
jsx表示对象
两种语法相同
jsx语法一:
const element = (<h1 className='green'>wangwanqi </h1>)
jsx语法二:
const element = React.createElement('h1',{ className:'green'},wangwanqi)
简化过后的结构:
// 注意:这是简化过的结构
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
7.函数组件与class组件
-
定义函数组件
function Welcome(props) { return <h1>Hello, {props.name}</h1>; }class组件
-
class组件 es6语法
class Welcome extends React.component{
render(){
return <h1>Hello, {props.name}</h1>;
}
}
- 渲染组件
React元素可以是用户自定义的组件
const element = <Welcome name='王万琦'>
#当React元素为用户自定义组件是 他会将jsx所接收的属性attributes以及子组件(clildren)转换成单个对象传递给组件
#这个对象称为props
例如:
function Welcome (props) {
return <h1 > {props.name}</h1>
}
const element =<Welcome name='王万琦'>
ReactDOM.render(
element,
document.getElementById('root')
);
#过程
1.调用render函数, 并传入<Welcome name='王万琦'>
2.React调用Welcome组件, 并将{name:'王万琦'}作为props传入
3.Welcome组件将<h1 >王万琦</h1> 元素作为返回值
4.ReactDom将Dom高效的更新为<h1 >王万琦</h1>
-
组件名称必须以大写字母开头,如果是小写字母 React会将其认为原生dom标签
-
组合组件
#组件可以在其输出时引用其他组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
- 组件的封装
const GetAuthor = function (props) {
return (
<div className="author">
<div>姓名: {props.author}</div>
<div>住址: {props.adress}</div>
<div>联系方式: {props.tel}</div>
</div>
)
}
export default GetAuthor
8.state与生命周期
state与props类似 但是state是私有的 , 并且完全受控于当前组件
- props的只读性
组件无论是使用函数声明 还是 class声明 , 都绝不能修改自身的props
所有React组件都必须像纯函数那样保护他们的props不被更改,即传入的props
不能发生任何变动
- 将函数组件转换成class组件
- 创建一个同名的es6class 并且继承React.component
- 创建一个空的render体 ,
- 将函数体转移到render中
- 在render函数中将props中引用的props.author 等属性改为this.props.author
- 删除剩余的函数声明
class Getauthor extends React.Component(
render() {
return (
<div className="author">
<div>姓名: {this.props.author}</div>
<div>住址: {this.props.adress}</div>
<div>联系方式: {this.props.tel}</div>
</div>
)
}
)
- 向class组件中添加局部的state
通过以下三部将date从props移动到state中
- 把render()方法中的this.props的date替换成this.state.date
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } }
- 添加一个class构造函数, 然后将函数中的this.state
class Clock extends React.Component {
//只有使用super 才能使用this关键字 否则会报错 这是应为子类实例的构建基于父类实例 只有super方法才能调用父类实例
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>
);
}
}
通过以下方式将props传递到父类的构造函数中
constructor(props) { super(props); this.state = {date: new Date()}; }
- 3.移除组件Clock元素中的date属性
ReactDOM.render( <Clock />, document.getElementById('root') );
-
4.设置计时器并且每秒更新他
-
将声明周期方法添加到class中
当组件第一次被渲染到dom的时候就设置一个计时器 在react中称为挂载mount
当dom中组件被删除的时候应该清除计时器 称为卸载 unmount
我们可以为class组件声明一些特殊的方法 当组件挂载或卸载时去执行这些方法 这些方法称为声明周期方法
componentDidMount 挂载 componentWillUnmount 卸载
完整代码实例
// const GetAuthor = function (props) { // return ( // <div className="author"> // <div>姓名: {props.author}</div> // <div>住址: {props.adress}</div> // <div>联系方式: {props.tel}</div> // <div>当地时间: {new Date().toLocaleTimeString()}</div> // </div> // ) // } // 使用state import React from 'react' // 创建class类 继承于React.component // 添加render方法 // super定义this 并且传入props // 组件中删除传入的方法 // 这样state就变成了响应式的 不需要书写 循环异步定时器 console.log(React) class GetAuthor extends React.Component { constructor(props) { super(props) // 定义state初始参数 this.state = { date: new Date(), } } render() { return ( <div className="author"> <div>姓名: {this.props.author}</div> <div>住址: {this.props.adress}</div> <div>联系方式: {this.props.tel}</div> <div>当地时间: {this.state.date.toLocaleTimeString()}</div> </div> ) } trick() { // 不能直接直接修改state中的内容 这是React的保护机制 // this.state.date = new Date() // 正确写法: let tempState = JSON.parse(JSON.stringify(this.state)) tempState.date = new Date() this.setState(tempState) } // `挂载执行 componentDidMount() { // 不能这样写 定时器中的函数需要为箭头函数 来获取this指向 // this.timeID = setInterval(this.trick(), 1000) this.timeID = setInterval(() => { this.trick() }, 1000) } // 卸载执行函数 componentWillUnmount() { window.clearInterval(this.timeID) } } export default GetAuthor
响应刷新原理:王万琦
浏览器每秒都会调用一次
tick()
方法。 在这方法之中,Clock
组件会通过调用setState()
来计划进行一次 UI 更新。得益于setState()
的调用,React 能够知道 state 已经改变了,然后会重新调用render()
方法来确定页面上该显示什么。这一次,render()
方法中的this.state.date
就不一样了,如此以来就会渲染输出更新过的时间。React 也会相应的更新 DOM。
9.正确使用state
不要直接修改state 如要修改 使用setState重新定义
构造函数是唯一可以给this.state赋值的地方
State的更新可能是异步的 处于性能考虑 React可能把多个setState()调用合并成一个调用
// Wrong this.setState({ counter: this.state.counter + this.props.increment, });
constructor(props) { super(props); this.state = { posts: [], comments: [] }; }
可以分别调用 不用重新设置
componentDidMount() { fetchPosts().then(response => { this.setState({ posts: response.posts }); }); fetchComments().then(response => { this.setState({ comments: response.comments }); }); }
10.事件处理
React事件的命名采用小驼峰命名 而不是全小写
使用jsx语法是需要传入一个函数 作为事件处理函数,而不是字符串
传统html
<button onclick="activateLasers()">
Activate Lasers
</button>
React事件处理
<button onClick={activateLasers}> Activate Lasers </button>
使用的方法必须更改this指向 方法如下,
如果不更改this指向 调用方法会报undefined
constructor(props) { super(props); this.state = {isToggleOn: true}; // 为了在回调中使用 `this`,这个绑定是必不可少的 this.handleClick = this.handleClick.bind(this); } <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
参数传递的两种方式
更改this指向方式
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
函数组件渲染是书写的两种方式
<ul>
{/* <ListItems></ListItems> */}
{ListItems()}
</ul>
11.表单
- input
- texxarea
- select
以上三种都是通过change进行将更改的数据设置成state中的数据
从而是state变成唯一数据源
注意
: React的更新时异步的所有更新state之后获取state有可能不是最新的数据,如果是表单checkbox 可能获取到相反的结果#原因: React中的state更新是异步的,不能依赖state中的计算结果去进行下一步的state import React from 'react' class CheckGroup extends React.Component { constructor(props) { super(props) //访问props // 设置默认赋值 this.state = { author: 'wangwanqi', isCheck: true, } this.handleChange = this.handleChange.bind(this) } render() { return ( <div> <label> 姓名: <input type="text" name="author" value={this.state.author} onChange={this.handleChange} /> </label> <label> 统计登录次数: <input type="checkbox" onChange={this.handleChange} name="isCheck" checked={this.state.isCheck} /> </label> </div> ) } handleChange(event) { const target = event.target const type = target.type const name = target.name const value = type === 'checkbox' ? target.checked : target.value this.setState({ [name]: value, }) /**只能异步获取**/ setTimeout(() => { console.log(this.state) }, 1000) } } export default CheckGroup
实现同步更新方式
第一种:
添加异步函数 定时器
第二种:
test(){
this.setState((props)=>({//props指定的是state对象
num:props.num+1 //实现state的num属性值加1
}));
}
12.状态提升
通常, 多个组件需要反应相同的变化数据 这是需要共享状态提升到最近的共同父组件中
个人理解: 多个子组件如果其中一个组件变化了 其他子组件同步发生变化
主要方式:
- 将子组件的值设置为父组件传递进来的值
- 检测子组件的变化
- 子组件变化后 执行父组件传递进来的props中的方法
- 父组件定义传给子组件的方法,接受子组件传递进来的值
- 将子组件传递进来的值赋值给父组件中的state
- 这样子组件都是用的父组件传递进来的值 完成妆台同步
<!DOCTYPE html> <html> <head> <title>Demo</title> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone"></script> </head> <body> <div id="app"></div> <script type="text/babel"> class Input extends React.Component { constructor(props) { super(props) this.handleChange = this.handleChange.bind(this) } handleChange(e) { this.props.onContentChange(e.target.value) } render() { return ( <input type='text' value={ this.props.content } onChange={ this.handleChange } /> ) } } //父组件 class AllInput extends React.Component { constructor(props) { super(props) this.state = { content: '' } this.handleContentChange = this.handleContentChange.bind(this) } handleContentChange(newContent) { this.setState({ content: newContent }) } render() { return ( <div> <Input content={ this.state.content } onContentChange={ this.handleContentChange }/> <br /><br /> <Input content={ this.state.content } onContentChange={ this.handleContentChange }/> </div> ) } } ReactDOM.render( <AllInput />, document.getElementById('app') ) </script> </body> </html>
13.组合与继承
组件可以接受任意 props,包括基本数据类型,React 元素以及函数。