React专栏 【1】React-Router 5 快速上手指南! 【2】React-Router6 全面解析 ??? 【3】Redux+React-Redux 最新入门实战指南? 【4】关于React,这几个常用技巧你应该知道!
ReactDOM.render() 方法渲染页面
注意:如果在html页面中使用 React,需要导入三个包。其中,react.development.js 必须在react-dom.development.js之前引入,下面为了方便,便不再引入。
<head>
<!-- 注意: 部署时,将 "development.js" 替换为 "production.min.js"。-->
<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@6/babel.min.js"></script>
</head>
</head>
<body>
<!-- 准备一个容器 -->
<div id="app"></div>
<!-- 注意:此处必须写babel -->
<script type="text/babel">
// 1. 创建虚拟DOM
const VDOM = Hello React
// 2. 渲染虚拟DOM到页面(虚拟DOM, 容器)
ReactDOM.render(VDOM,document.getElementById('app'))
</script>
</body>
注意:上面都是在一个html文件里面编写react,为了方便 jsx 的部分会在这里说明,其他的会在脚手架创建的项目中说明
<body>
<div id="app"></div>
<script type="text/javascript">
// 使用纯js创建虚拟DOM太繁琐,可读性差,不利于维护
const VDOM = React.createElement('h1',{id:'title'},React.createElement('span',{},'Hello React'));
ReactDOM.render(VDOM,document.getElementById('app'))
</script>
</body>
<body>
<!-- 准备一个容器 -->
<div id="app"></div>
<script type="text/babel">
// 使用 jsx 创建虚拟DOM便捷高效
const VDOM = (
<span>Hello React</span>
)
ReactDOM.render(VDOM,document.getElementById('app'))
</script>
</body>
拓展:使用 jsx 创建的DOM最终会被转成 React element 元素,我们一般直接使用 jsx 即可
const VDOM = Hello JSX!htmlForstyle={{color:'blue',fontSize:'30px'}} 的形式去写<body>
<div id="app"></div>
<script type="text/babel">
const myId = 'aTgUiGu'
const myData = 'Hello React'
const VDOM = (
<div>
<h2 id={myId.toLowerCase()} className="title">
<span style={{color:'blue',fontSize:'30px'}}>{myData.toLowerCase()}</span>
</h2>
<input type='text'/>
<!--能运行,但会报错,因为html并没有这个标签-->
<good>123</good>
</div>
)
ReactDOM.render(VDOM, document.getElementById('app'));
</script>
</body>
ReactDOM.render(virtualDOM, containerDOM)
作用: 将虚拟DOM元素渲染到页面中的真实容器DOM中显示
参数说明
create-react-app Hello
注意:需要提前全局安装 react 的脚手架 npm i -g create-react-app
public ---- 静态资源文件夹
favicon.icon ------ 网站页签图标
index.html -------- 主页面
logo192.png ------- logo图
logo512.png ------- logo图
manifest.json ----- 应用加壳的配置文件
robots.txt -------- 爬虫协议文件
src ---- 源码文件夹
App.css -------- App组件的样式
App.js --------- App组件
App.test.js ---- 用于给App做测试
index.css ------ 样式
index.js ------- 入口文件
logo.svg ------- logo图
reportWebVitals.js --- 页面性能分析文件(需要web-vitals库的支持)
setupTests.js ---- 组件单元测试的文件(需要jest-dom库的支持)
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App/>, document.getElementById('root'))
React18
import { createRoot } from "react-dom/client";
import App from './App'
const root = createRoot(document.getElementById('root'))
root.render(<App/>)
ReactDOM.render() 时,必须写成标签形式
<body>
<div id="app"></div>
<script type="text/babel">
// 创建函数式组件
function MyComponent() {
console.log(this); // undefined
return (
<h2>我是用函数定义的组件(使用于【简单组件】的定义)</h2>
)
}
ReactDOM.render(<MyComponent/>, document.getElementById('app'))
</script>
</body>
拓展:执行了 ReactDOM.render() 之后,发生了什么?
<body>
<div id="app"></div>
<script type="text/babel">
// 创建类式组件
class MyComponent extends React.Component {
render() {
// render中的this是谁? —— MyComponent的实例对象 <=> MyComponent组件实例对象
console.log('render中的this',this); // MyComponent{}
return <h2>我是用类定义的组件(使用于【复杂组件】的定义)</h2>
}
}
ReactDOM.render(<MyComponent/>, document.getElementById('app'))
</script>
</body>
拓展: 执行了ReactDOM.render()之后,发生了什么?
<button onClick={this.handleClick}>点击</button>
3.2 然后在类中自定义回调函数,要用赋值语句的形式 + 箭头函数。说明:
<body>
<div id="app"></div>
<script type="text/babel">
class Demo extends React.Component {
// 失焦事件
blurShowData = (e) => {
// 这个 e 就是当前发生事件的 DOM 元素
console.log(e.target);
alert(e.target.value)
}
render() {
// React推荐使用行内形式
return (
<div>
<input onBlur={this.blurShowData} type="text" placeholder="表单失焦弹出数据"/>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('app'))
</script>
</body>
4. 事件绑定中处理 this 的三种方案
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
message: "你好啊",
counter: 100
}
// bind绑定this
this.btnClick = this.btnClick.bind(this);
}
render() {
return (
<div>
{/* 1.方案一: bind绑定this(显示绑定) */}
<button onClick={this.btnClick}>按钮1</button>
<button onClick={this.btnClick}>按钮2</button>
<button onClick={this.btnClick}>按钮3</button>
{/* 2.方案二: 定义函数时, 使用箭头函数 */}
<button onClick={this.increment}>+1</button>
{/* 2.方案三(推荐): 直接传入一个箭头函数, 在箭头函数中调用需要执行的函数*/}
<button onClick={() => { this.decrement("why") }}>-1</button>
</div>
)
}
btnClick() {
console.log(this.state.message);
}
// increment() {
// console.log(this.state.counter);
// }
// 箭头函数中永远不绑定this
// ES6中给对象增加属性: class fields
increment = () => {
console.log(this.state.counter);
}
decrement(name) {
console.log(this.state.counter, name);
}
}
ReactDOM.render(<App/>, document.getElementById("app"));
</script>
<body>
<div id="app"></div>
<script type="text/babel">
class Component extends React.Component {
state = {
msg: 'hello state'
}
render() {
return {this.state.msg}
}
}
ReactDOM.render(<Component/>, document.getElementById('app'))
</script>
</body>
1.3 如何修改state 中的值
使用:必须调用 React 内置的 setState() 方法去修改state中的值,通过this 调用即可
说明:该 setState 在父类的 React.component 类身上,使用 this 顺着原型链就能找到
<body>
<div id="app"></div>
<script type="text/babel">
class Component extends React.Component {
state = {
msg: 'hello state'
}
changeMsg = () => {
// 调用 setState 方法,更新数据
this.setState({
msg: 'hello React'
})
}
render() {
return {this.state.msg}
}
}
ReactDOM.render(<Component/>, document.getElementById('app'))
</script>
</body>
强烈注意:
this.changeWeather = this.changeWeather.bind(this)
ReactDOM.render(<Person name="张三" age={19}/>, document.getElementById('app'))
注意:如果要传递 number 类型数据,必须使用{}
2. 第二种写法:事先准备好一个数据对象,然后通过拓展运算符传递
const data = {name:"张三", age:19}
ReactDOM.render(<Person {...data}/>, document.getElementById('app'))
注意:使用 this.props 获取数据时,属性名要与数据对象保持一致
说明:正常情况下是无法对一个对象直接使用拓展运算符的,是因为 babel + react.development.js 的加持下,才允许这么写,仅可以在组件标签中这么写
3. 从组件实例 this 上的 props 获取属性值
const { name, age } = this.props<body>
<div id="app"></div>
<script type="text/babel">
class Person extends React.Component {
render() {
// props 会接收到组件标签上的属性值
const { name, age } = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
// 1. 将属性值只在写在组件标签上
// ReactDOM.render(<Person name="张三" age="19"/>, document.getElementById('app'))
// 2. 另一种写法,采用展开运算符
const data = {name:"张三", age:19}
ReactDOM.render(<Person {...data}/>, document.getElementById('app'))
</script>
</body>
2.4 对 props 进行限制
<body>
<div id="app"></div>
<div id="app1"></div>
<div id="app2"></div>
<script type="text/babel">
class Person extends React.Component {
// 给 Person 添加静态属性,(给类自身添加属性)
static propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
sex: PropTypes.string,
speak:PropTypes.func,
}
// 指定默认值
static defaultProps = {
age: 18,
sex: '未知'
}
render() {
const { name, age, sex } = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
)
}
}
ReactDOM.render(<Person name="小明" age={19} sex="男"/>, document.getElementById('app'))
ReactDOM.render(<Person name="小红" sex="女"/>, document.getElementById('app1'))
ReactDOM.render(<Person name="小强" age={34}/>, document.getElementById('app2'))
</script>
</body>
注意:如果在 html 页面对 props 进行限制,必须导入 prop-types.js 这个包
2.5 在函数式组件使用 props
<body>
<div id="app"></div>
<script type="text/babel">
// 接收 props,即可拿到标签属性的值
function Person(props) {
return (
<ul>
<li>姓名:{props.name}</li>
<li>年龄:{props.age}</li>
</ul>
)
}
// 函数式组件对props的值进行限制,只能通过这种方式
Person.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
}
Person.defaultProps = {
age: 18,
}
ReactDOM.render(<Person name="jack"/>, document.getElementById('app'))
</script>
</body>
注意:React 官方不推荐字符串这种形式的写法,“因为 string 类型的 refs 存在 一些问题。它已过时并可能会在未来的版本被移除。”
<body>
<div id="app"></div>
<script type="text/babel">
class Demo extends React.Component {
// 点击事件
clickShowData = () => {
// 通过 this.refs 就可拿到对应 ref 属性值的元素
const { input1 } = this.refs
alert(input1.value)
}
render() {
// 1. react会收集添加了 ref 属性的元素
return (
<div>
<input ref="input1" type="text" placeholder="点击按钮弹出数据"/>
<button onClick={this.clickShowData}>点击弹出左边的数据</button>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('app'))
</script>
</body>
3.2 回调函数形式的 ref
<input ref={c=>this.input1=c} type="text" />
回调函数里的含义是:把 ref 所在的节点挂载到组件的实例 this上,名字为 input1
2. 直接从组件实例 this 即可拿到节点元素
<body>
<div id="app"></div>
<script type="text/babel">
class Demo extends React.Component {
// 点击事件
clickShowData = () => {
// 2. 直接从组件实例 this 拿到节点元素
const { input1 } = this
alert(input1.value)
}
render() {
// 1. ref 为回调函数的形式,react 内部会调用
// 回调函数里的含义是:把 ref 所在的节点挂载到组件的实例 this上,名字为 input1
return (
<div>
<input ref={c=>this.input1=c} type="text" placeholder="点击按钮弹出数据"/>
<button onClick={this.clickShowData}>点击弹出左边的数据</button>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('app'))
</script>
</body>
3.3 createRef 的形式
React.createRef() 的形式获取 DOM 元素,(直接把 inputRef 绑定到 组件实例 this上,直接 this.inputRef.current 可以获取)<body>
<div id="app"></div>
<script type="text/babel">
class Demo extends React.Component {
// 使用 React.createRef() 的形式获取 DOM 元素
inputRef = React.createRef()
// 点击事件
clickShowData = () => {
// 2. 直接从组件实例 this 拿到节点元素
console.log(this);
const input = this.inputRef.current;
alert(input.value)
}
render() {
return (
<div>
<input ref={this.inputRef} type="text" placeholder="点击按钮弹出数据"/>
<button onClick={this.clickShowData}>点击弹出左边的数据</button>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('app'))
</script>
</body>
3.4 总结
{/* <div>哈哈哈</div> */}<body>
<div id="app"></div>
<script type="text/babel">
class Login extends React.Component {
// 展示输入数据
showData = (e) => {
e.preventDefault() // 阻止表单提交
const {username, password} = this
alert(`用户名:${username.value},密码:${password.value}`)
}
render() {
return (
<form action="https://www.baidu.com" onSubmit={this.showData}>
用户名<input ref={c=>this.username=c} type="text" name="username"/><br/>
密码:<input ref={c=>this.password=c} type="password" name="password"/>
<button>提交</button>
</form>
)
}
}
ReactDOM.render(<Login/>, document.getElementById('app'))
</script>
</body>
说明:这里其实是通过 ref 获取当前DOM元素,就可以拿到输入的 value 值
<body>
<div id="app"></div>
<script type="text/babel">
class Login extends React.Component {
state = {
username: '',
password: ''
}
// 保存 username 到 state 中
saveUsername = (e) => {
this.setState({
username: e.target.value
})
}
// 保存 password 到 state 中
savePassword = (e) => {
this.setState({
password: e.target.value
})
}
// 展示输入数据
showData = (e) => {
e.preventDefault()
const { username, password } = this.state
alert(`用户名:${username},密码:${password}`)
}
render() {
return (
<form action="https://www.baidu.com" onSubmit={this.showData}>
用户名<input onChange={this.saveUsername} type="text" name="username"/><br/>
密码:<input onChange={this.savePassword} type="password" name="password"/>
<button>提交</button>
</form>
)
}
}
ReactDOM.render(<Login/>, document.getElementById('app'))
</script>
</body>
说明:这里是监听了 input 的 change 事件,当内容发生变化,就会立即调用。然后会把最新值存入 state 中维护。
注意:这里的 change 事件分别写了两个函数,万一后面有更多的需要监听,会非常的繁琐。所以后面会使用 函数柯里化 进行优化。
<body>
<div id="app"></div>
<script type="text/babel">
class Demo extends React.Component {
// 存放用户输入的数据
state = {
msg: ''
}
// 监听input的change事件,将数据存入state中
saveMsg = (e) => {
this.setState({
msg: e.target.value
})
}
render() {
return (
<div>
<h2>实时显示你输入的数据:{this.state.msg}</h2>
<input onChange={this.saveMsg} type="text" placeholder="请输入"/>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('app'))
</script>
</body>
说明:这里是监听了 input 的 change 事件,然后将最新的数据存入 state 中,然后在 jsx 中展示
<body>
<div id="app"></div>
<script type="text/babel">
class Login extends React.Component {
state = {
username: '',
password: ''
}
// 保存表单数据到 state 中,这里就是高阶函数,并且实现了函数的柯里化
saveFormData = (dataType) => {
// 返回一个函数,给事件去调用
// 当注册事件时,直接调用并参入参数,那么事件 e 就在 return 的函数参数里
return (e) => {
// 当接收一个变量作为对象的的键时,必须使用 []
this.setState({
[dataType]: e.target.value
})
}
}
// 展示输入数据
showData = (e) => {
e.preventDefault()
const { username, password } = this.state
alert(`用户名:${username},密码:${password}`)
}
render() {
return (
<form action="https://www.baidu.com" onSubmit={this.showData}>
用户名<input onChange={this.saveFormData('username')} type="text" name="username"/><br/>
密码:<input onChange={this.saveFormData('password')} type="password" name="password"/>
<button>提交</button>
</form>
)
}
}
ReactDOM.render(<Login/>, document.getElementById('app'))
</script>
</body>
说明:
生命周期的三个阶段(旧)
生命周期的三个阶段(新)
a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
(1).若虚拟DOM中内容没变, 直接使用之前的真实DOM
(2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
b. 旧虚拟DOM中未找到与新虚拟DOM相同的key
根据数据创建新的真实DOM,随后渲染到到页面
yarn add pubsub-js
import PubSub from 'pubsub-js'
// PubSub.publish(发布名称, 数据)
PubSub.publish('coder', {name: 'bin', age: 21})
subscribe() 订阅,用于接收数据,一般在 componentDidMount 生命周期函数中执行
import PubSub from 'pubsub-js'
// 要在组件挂载完后开始订阅
componentDidMount() {
// PubSub.subscribe(发布名称, 回调函数)
this.token = PubSub.subscribe('coder', (msg, data) =>{
console.logI(msg) // coder(这个msg没啥用,但必须写,否则报错,人家就这么设计)
console.log(data) // {name: 'bin', age: 21}
})
}
unsubscribe(),用于取消订阅,谁订阅,谁取消,一般在 componentWillUnmount 生命周期中执行
// 组件将要卸载时,取消订阅
componentWillUnmount() {
PubSub.unsubscribe(this.token) // 值为订阅时的返回值
}
每文一句:世界上三种东西最宝贵——知识、粮食和友谊。本次的分享就到这里,如果本章内容对你有所帮助的话欢迎点赞+收藏。文章有不对的地方欢迎指出,有任何疑问都可以在评论区留言。希望大家都能够有所收获,大家一起探讨、进步!
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI
这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub
我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,
Ⅰ软件测试基础一、软件测试基础理论1、软件测试的必要性所有的产品或者服务上线都需要测试2、测试的发展过程3、什么是软件测试找bug,发现缺陷4、测试的定义使用人工或自动的手段来运行或者测试某个系统的过程。目的在于检测它是否满足规定的需求。弄清预期结果和实际结果的差别。5、测试的目的以最小的人力、物力和时间找出软件中潜在的错误和缺陷6、测试的原则28原则:20%的主要功能要重点测(eg:支付宝的支付功能,其他功能都是次要的)80%的错误存在于20%的代码中7、测试标准8、测试的基本要求功能测试性能测试安全性测试兼容性测试易用性测试外观界面测试可靠性测试二、质量模型衡量一个优秀软件的维度①功能性功
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称