摘要:即组件内部可以引用其他组件,如注意在中,组件必须返回单一的根元素,这也是为什么组件中需要用标签包裹的原因。那么,这种情况下,为我们提供了生命周期的钩子函数,方便我们进行使用。
学和使用react有一年多了,最近想在梳理一下react基础知识,夯实基础,激流勇进~ 关于reacr-router,redux,redux-saga后续都会慢慢输出,希望各位看官老爷持续关注~~要是能给个赞鼓励一下就更赞了~
提醒一下: 看完之后抓紧时间趁热打铁,redux,react-redux,redux-saga
一篇文章总结redux、react-redux、redux-saga
react基础知识速览 1、什么是JSX?一个JSX语法的示例,如下所示
const element =Hello, world!
;
这种语法形式,既不是HTML,也不是字符串,而是称之为JSX,是React里用来描述UI和样式的语法,JSX最终会被编译为合法的JS语句调用(编译器在遇到{时采用JS语法进行解析,遇到<就采用HTML规则进行解析)
2、嵌入表达式JSX中,可以使用花括号{}嵌入任意的JavaScript合法表达式,如:2 + 2、user.firstName、formatName(user)都是合法的。示例如:
const user = {
firstName: "Zhang",
lastName : "Busong"
};
const elem = (
Hello, {formatName(user)}
);
/*
这里的(),实际上是可选的,但是React推荐加入(),这样子就会被视为一个表达式,而不会导致
自动插入分号的问题
*/
ReactDOM.render(
element,
document.getElementById("app")
)
3、JSX也是一种表达式
JSX本身也是一种表达式,所以它可以像其他表达式一样,用于给一个变量赋值、作为函数实参、作为函数返回值,等等。如:
function getGreeting(user) {
if (user) {
return Hello, {formatName(user)}
}
return Hello, Guest!
;
}
注意: 1、在JSX中,声明属性时不要使用引号,如果声明属性的时候使用引号,那么将被作为字符串解析,而不会被作为一个表达式解析,如:
"{user.firstName}" lastName={user.lastName}>
解析后,可以得到:
"{user.firstName}" lastName="Lau">
因此,当我们需要使用一个字符串字面量的时候,可以使用引号,但是如果要作为表达式解析的时候,则不应当使用引号 2、在JSX中,有些属性名称需要进行特殊处理。如class应该用className代替,tabindex则用tabIndex代替。这是因为JSX本质上更接近于JavaScript,而class是JavaScript中的保留字。同时,应该使用camelCase来命名一个属性,而不是使用HTML的属性命名方式 3、JSX本身已经做了防注入处理,对于那些不是明确编写的HTML代码,是不会被解析为HTML DOM的,ReactDOM会将他们一律视为字符串,在渲染完成前就转化为字符串,所以可以防止XSS攻击 4、如果JSX标签是闭合的,那么结尾需要用/>,另外,JSX标签是可以互相嵌套的,这和HTML里是一样的
4、JSX实质JSX通过babel编译,而babel实际上把JSX编译给React.createElement()调用。如下JSX代码:
const element = ("greeting"> Hello, world!
);
是等同于以下的语句的:
const elem = React.createElement(
"h1",
{className: "greeting"},
"Hello, world!"
);
React.createElement()方法会首先进行一些避免BUG的检查,然后返回类似以下例子的对象:
const element = {
type: "h1",
props: {
className: "greeting",
children: "Hello, world"
}
}
这样的对象,则称为React元素,代表所有呈现在屏幕上的东西。React正是通过读取这些对象来构建DOM,并且保持数据和UI同步的
5、元素渲染元素(elements)是构成React应用的最小单元,元素描述了想要在屏幕中看到的内容,如:
const element =Hello, world
;
和DOM元素不同的是,React元素是纯对象,创建的代价低。并且React会进行优化处理,只把有必要的变化更新到DOM上。此外,元素和组件的概念,是不一样的,组件是由元素组成的。
6、将元素渲染进DOM在React中,使用ReactDOM.render()方法来将React元素渲染进一个DOM中。如:
ReactDOM.render(
element,
document.getElementById("root")
)
React元素是不可变的,所以一旦一个元素创建完成后,我们是无法改变其内容或者属性的。一个元素就像是动画里的一帧,它代表UI在某一时间点的样子。如果非要使用元素来构成可变化的UI界面,就需要使用setInterval了,如:
function tick() {
const element = (
Now is {new Date().toLocaleTimeString()}
);
ReactDOM.render(
element,
document.getElementById("root")
);
}
setInterval(tick, 1000);
在实际开发中,大多数React应用只会调用一次ReactDOM.render(),所以更好的方式是使用有状态组件
7、组件和Props组件(component)能够将UI划分为独立的、可复用的部分,这样我们就只需专注于构建每一个多带带的部件。 从概念上看,组件就像是函数:接受任意的输入(称为属性,Props),返回React元素。React中有两种定义组件的方式:函数定义和类定义
1、函数定义组件这种方式是最简单的定义组件的方式,就像写一个JS函数一样,如:
function Welcome (props) {
return Hello, {props.name}
;;
}
2、类定义组件
还可以使用ES6里的类来定义一个组件,如下所示:
class Welcome extends React.Component {
render () {
return Hello, {this.props.name};
}
}
这种方式比起函数定义方式则更加灵活
3、组件渲染先前,我们遇到的React元素只是呈现一个DOM标签,如:
const element =
然而,React元素也可以是用户自定义的组件,如:
const element ="Tom" />
Welcome组件中声明了一个属性name="Tom",而这个属性,将以props.name的方式传递给组件,如下方式:
function Welcome (props) {
return Hello, {props.name}
;
}
此时,对于以下的代码:
ReactDOM.render(
"张不怂" />,
document.getElementById("root")
)
最终就会以Hello, 张不怂
的方式呈现。在这个过程中,发生了如下的事情:
对
React将{ name: "张不怂" }作为props实参来调用Welcome组件
Welcome完成渲染,返回Hello, 张不怂
元素
ReactDOM计算最小更新代价,然后更新DOM
4、组合组件组件是可以组合的。即组件内部可以引用其他组件,如:
function Welcome (props) {
return Hello, {props.name}
;
}
function App () {
return (
"Tom" />
"Jack" />
"Mike" />
)
}
ReactDOM.render(
,
document.getElementById("root")
)
注意: 在React中,组件必须返回单一的根元素,这也是为什么App组件中需要用 考虑以下这种情况: 这种函数称为纯函数:它不改变自己的输入值,且总是对相同的输入返回相同的结果。
与之对立的,则是非纯函数,如: 非纯函数在函数内改变了输入的参数。在React中,无论是通过function还是class声明组件,我们都不应该修改它自身的属性(props)。虽然React相当灵活,但是它也有一个严格的规定:所有的React组件都必须像纯函数那样来使用它们的props 使用类定义组件有一些额外的好处,如拥有本地状态这一特性。
以下是一个类定义组件 需要注意的有: 类名即为组件名(无论是函数定义组件还是类定义组件,组件名称的首字母都必须大写,并且继承自React.Component) 使用 render() 方法,用来返回需要呈现的内容 state是属于一个组件自身的。我们可以在类的构造函数constructor中来初始化状态,如: 如此一来,我们就可以在render()函数中使用this.state.xxx来引用一个状态 在应用里,往往都会有许许多多的组件。在组件销毁后,回收和释放它们所占据的资源非常重要。
在时钟应用的例子里,我们需要在第一次渲染到DOM的时候设置一个定时器,并且需要在相应的DOM销毁后,清除这个定时器。那么,这种情况下,React为我们提供了生命周期的钩子函数,方便我们进行使用。在React中,生命周期分为:
1)Mount 已插入真实DOM
2)Update 正在重新渲染
3)Unmount 已移出真实DOM
而相应的,生命周期钩子函数有: componentWillMount componentDidMount componentWillUpdate(newProps, nextState) componentDidUpdate(prevProps, prevState) componentWillUnmount() 此外,还有两种特殊状态的处理函数: componentWillReceiveProps(nextProps) 已加载的组件收到新的参数时调动 shouldComponentUpdate(nextProps, nextState) 组件判断是否重新渲染时调用 因此,基于生命周期钩子函数,我们可以实现一个时钟应用如下: 需要注意的是:
1)render()里用不到的state,不应该声明在state里
2)不能直接使用this.state.xxx = xxx的方式来改变一个state的值,应该使用this.setState()。如: this.setState()会自动覆盖this.state里相应的属性,并触发render()重新渲染。
3)状态更新可能是异步的
React可以将多个setState()调用合并成一个调用来提升性能。且由于this.props和this.state可能是异步更新的,所以不应该依靠它们的值来计算下一个状态。这种情况下,可以给setState传入一个函数,如: React元素的事件与DOM元素类似,不过也有一些区别,如:
1)React事件使用camelCase命名(onClick),而不是全小写的形式(onclick)
2)使用JSX,传入的是事件的句柄,而不是一个字符串
如以下的HTML: 使用React的方式描述如: 还有一个不同在于,在原生DOM中,我们可以通过返回false来阻止默认行为,但是这在React中是行不通的,在React中需要明确使用preventDefault()来阻止默认行为。如: 这里,事件回调函数里的event是经过React特殊处理过的(遵循W3C标准),所以我们可以放心地使用它,而不用担心跨浏览器的兼容性问题。
注意: 在使用事件回调函数的时候,我们需要特别注意this的指向问题,因为在React里,除了构造函数和生命周期钩子函数里会自动绑定this为当前组件外,其他的都不会自动绑定this的指向为当前组件,因此需要我们自己注意好this的绑定问题,
通常而言,在一个类方式声明的组件里使用事件回调,我们需要在组件的constructor里绑定回调方法的this指向,如: 当然,我们还有另外一种方法来使用箭头函数绑定指向,就是使用实验性的属性初始化语法,如: 3)像事件处理程序传递参数
我们可以为事件处理程序传递额外的参数,方式有以下两种: 需要注意的是,使用箭头函数的情况下,参数e要显式传递,而使用bind的情况下,则无需显式传递(参数e会作为最后一个参数传递给事件处理程序) 在React里,我们可以创建不同的组件来封装我们需要的功能。我们也可以根据组件的状态,只渲染组件中的一部分内容,而条件渲染就是为此而准备的。在React中,我们可以像在JavaScript中写条件语句一样地写条件渲染语句,如: 这将渲染出: 我们也可以使用变量来存储元素,如: 由于JavaScript语法对待&&运算符的性质,我们也可以使用&&运算符来完成条件渲染,如: 当props.isLogined为false的时候,就会渲染出: 我们可能已经发现了,其实JSX可以像一个表达式那样子灵活使用,所以,我们自然也可以使用三目运算符进行渲染,如: 有时候,我们希望是整个组件都不渲染,而不仅仅是局部不渲染,那么这种情况下,我们就可以在render()函数里返回一个null,来实现我们想要的效果,如: 注意: 组件里返回null不会影响组件生命周期的触发,如componentWillUpdate和componentDidUpdate仍然会被调用 在JavaScript中,我们可以使用map()函数来对一个数组列表进行操作,如: 同样的,在React里,我们也可以使用map()来进行列表渲染,如: 这将得到: 当然,我们还可以进行更好的封装,如: 当我们运行以上的代码的时候,会发现控制台提示:Each child in an array or iterator should have a unique "key" prop,因此,我们需要为列表项的每一个项分配一个key,来解决这个问题,通常而言,我们可以使用以下几种方式来提供key: 使用数据项自身的ID,如 使用索引下标(index),如: 但是React不推荐在需要重新排序的列表里使用索引下标,因为会导致变得很慢。 注意: 只有在一个项的同胞里区分彼此的时候,才需要使用到key,key不需要全局唯一,只需要在一个数组内部区分彼此时唯一便可。key的作用是给React一个提示,而不会传递给组件。如果我们在组件内需要同样的一个值,可以换个名字传递,如: 表单和其他的React中的DOM元素有所不同,因为表单元素生来就是为了保存一些内部状态。在React中,表单和HTML中的表单略有不同 HTML中,、、这类表单元素会维持自身状态,并根据用户输入进行更新。不过React中,可变的状态通常保存在组件的this.state中,且只能用setState()方法进行更新,如: 和HTML中不同的是,React中的textarea并不需要写成的形式,而是写成的形式便可。而对于HTML中的select标签,通常做法是: 但是React中,不需要在需要选中的option处加入selected,而只需要传入一个value,就会自动根据value来选中相应的选项,如: 那么如上述例子,C所在的这个option就会被选中 通常一个表单都有多个输入,如果我们为每一个输入添加处理事件,那么将会非常繁琐。好的一个解决办法是,使用name,然后根据event.target.name来选择做什么。如: 性别:
是否参加:"attend" type="checkbox" onChange={this.handleInputChange} checked={this.state.attend} /> 您的报名信息:{this.state.profile} 大多数情况下,使用受控组件实现表单是首选,在受控组件中,表单数据是交由React组件处理的。如果想要让表单数据由DOM处理(即数据不保存在React的状态里,而是保存在DOM中),那么可以使用非受控组件,使用非受控组件,可以无需为每个状态更新编写事件处理程序,使用ref即可实现,如: 对于非受控组件,如果要指定默认值,那么可以使用defaultValue,如: 相应的,type="checkbox"和type="radio",则使用defaultChecked 当需要几个组件共用状态数据的时候,可以使用状态提升技术。核心思想在于:把数据抽离到最近的共同父组件,父组件管理状态(state),然后通过属性(props)传递给子组件。如实现一个货币转换的组件,可以如下: 我们希望在RMB的输入表单上上输入的时候,USD的输入表单上的数值也同步更新,这种情况下,如果RMB组件自己管理自己的状态,是很难以实现的,因此,我们需要让这个状态提升自父组件进行管理。如下: {type}: type="text" value={value} onChange={this.handleChange} /> 最后定义一个共同的父组件,如下: Please Input: React推崇更多的是使用组合,而非使用继承。对于一些使用场景,React给出的建议如下: 当父组件不知道子组件可能的内容是什么的时候,可以使用props.children,如: 这将渲染得到: 我们还可以自定义名称,因为JSX实际上会被转化为合法的JS表达式,所以,还可以有: 这将渲染得到: 在Facebook的网站上,使用了数以千计的组件,但是实践证明还没有发现需要使用继承才能解决的情况。
属性和组合为我们提供了清晰的、安全的方式来自定义组件的样式和行为,组件可以接受任意元素,包括:基本数据类型、React元素、函数。
如果要在组件之间复用UI无关的功能,那么应该将其提取到多带带的JavaScript模块中,这样子可以在不对组件进行扩展的前提下导入并使用函数、对象、类 觉得对你有帮助,不妨点个 不妨再点个关注,不迷路,下一篇关于redux的明天就发!!~ 文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。 转载请注明本文地址:https://www.ucloud.cn/yun/7240.htmlfunction App () {
return (
5、属性是只读的
function sum (a, b) {
return a + b;
}
function withdraw (account, amount) {
account.total -= amount;
}
class Clock extends React.Component {
render () {
return (
Hello, world!
Now is {this.props.date.toLocaleTimeString()}
constructor (props) {
super(props)
this.state = {
date: new Date()
}
}
class Clock extends React.Component {
constructor (props) {
super(props);
this.state = {
date: new Date()
}
}
tick () {
this.setState({
date: new Date()
});
}
componentDidMount () {
this.timerId = setInterval(() => {
this.tick()
}, 1000);
}
componentWillUnmount () {
clearInterval(this.timerId);
}
render () {
return (
setName () {
this.setState({
name: "张不怂"
})
}
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
9、事件处理
function ActionLink () {
function handleClick (e) {
e.preventDefault();
alert("Hello, world!");
}
return (
"#" onClick={handleClick}>Click Me
);
}
class Counter extends React.Component {
constructor (props) {
super(props);
this.state = {
counter: 0
}
// 在这里绑定指向
this.increment = this.increment.bind(this);
}
increment () {
this.setState({
counter: this.state.counter + 1
});
}
render () {
return (
class Counter extends React.Component {
increment: () => {
this.setState({
counter: this.state.counter + 1
});
}
// ...
}
function Greet(props) {
const isLogined = props.isLogined;
if (isLogined) {
return
1、使用变量来存储元素
function LogBtn(props) {
var button;
const isLogined = props.isLogined;
if (isLogined) {
button =
} else {
button =
}
return
2、使用&&运算符进行渲染
function LogBtn(props) {
var button;
const isLogined = props.isLogined;
return (
3、使用三目运算符进行渲染
function LogBtn (props) {
const isLogined = props.isLogined;
return (
4、阻止整个组件的渲染
function LogBtn (props) {
const isLogined = props.isLogined;
const isShow = props.isShow;
if (isShow) {
return (
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(number => number*2);
console.log(doubled); // 得到[2, 4, 6, 8, 10]
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map(number => {
return (
{listItems}
,
document.getElementById("root")
)
function NumberList (props) {
const numbers = props.numbers;
const listItems = numbers.map(number => {
return (
{listItems}
}
const listItems = numbers.map((number, index) => {
const content = posts.map(post => (
12、表单
class NameForm extends React.Component {
constructor (props) {
super(props);
this.state = {
value: ""
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange (event) {
this.setState({
value: event.target.value
});
}
handleSubmit (event) {
alert("Your name is "+this.state.value);
event.preventDefault();
}
render () {
return (
)
}
}
class Form extends React.Component {
constructor (props) {
super(props);
this.state = {
name: "",
gender: "男",
attend: false,
profile: ""
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleInputChange (event) {
const target = event.target;
const value = target.type==="checkbox" ");${this.state.name},${this.state.gender},${this.state.attend ");活动`
});
event.preventDefault();
}
render () {
return (
value={this.state.name} onChange={this.handleInputChange} />
3、非受控组件
class NameForm extends React.Component {
constrcutor(props) {
super(props)
}
handleSubmit(event) {
console.log("A name was submitted: ", this.input.value)
event.preventDefault()
}
render() {
return (
)
}
}
type="text" defaultValue="Hello" ref={input => this.input = input} />
function USD2RMB (amount) {
return amount * 6.7925;
}
function RMB2USD (amount) {
return amount * 0.1472;
}
function convert (amount, typeFn) {
return typeFn(amount);
}
2、定义组件
class CurrencyInput extends React.Component {
constructor (props) {
super(props)
this.handleChange = this.handleChange.bind(this)
}
handleChange (event) {
this.props.onInputChange(event.target.value)
}
render () {
const value = this.props.value
const type = this.props.type
return (
class CurrencyConvert extends Component {
constructor (props) {
super(props);
this.state = {
type: "RMB",
amount: 0
}
this.handleRMBChange = this.handleRMBChange.bind(this);
this.handleUSDChange = this.handleUSDChange.bind(this);
}
handleRMBChange (amount) {
this.setState({
type: "RMB",
amount
});
}
handleUSDChange (amount) {
this.setState({
type: "USD",
amount
});
}
render () {
const type = this.state.type;
const amount = this.state.amount;
const RMB = type==="RMB" ");type==="USD" ");return (
14、组合vs继承
function Article (props) {
return (
function Article (props) {
return (
2、何时使用继承?
摘要:精读源码一共行,我们分析一下其精妙的方式。更多讨论讨论地址是精读新用法如果你想参与讨论,请点击这里,每周都有新的主题,周末或周一发布。前端精读帮你筛选靠谱的内容。 1 引言 很高兴这一期的话题是由 epitath 的作者 grsabreu 提供的。 前端发展了 20 多年,随着发展中国家越来越多的互联网从业者涌入,现在前端知识玲琅满足,概念、库也越来越多。虽然内容越来越多,但作为个体的...
摘要:再来做个练习,如果我们想要黄色,那就是把红色光跟绿色光混合起来,所以我们就把红色光跟绿色光像这样开到最大,你就能够看到黄色了。 网页使用到的色彩标示方法中,从古早时期大家都在用的16进位码(#000000)、RGB色值标示、HSL色彩标示,其中网页设计师最常使用的16进位色码标示法,而16进位码又是如何计算色彩的呢?有没有办法直接脑袋就把色彩算出来?HSL色彩该如何运用与记忆?有没有什...
摘要:再来做个练习,如果我们想要黄色,那就是把红色光跟绿色光混合起来,所以我们就把红色光跟绿色光像这样开到最大,你就能够看到黄色了。 网页使用到的色彩标示方法中,从古早时期大家都在用的16进位码(#000000)、RGB色值标示、HSL色彩标示,其中网页设计师最常使用的16进位色码标示法,而16进位码又是如何计算色彩的呢?有没有办法直接脑袋就把色彩算出来?HSL色彩该如何运用与记忆?有没有什...
摘要:传统算法的一大特点就是虚拟的算法,下图为实现流程图。如果的子节点仍有子节点依旧顺次执行。我们来观察下复杂度传统算法的复杂度为,单纯从看,复杂度不到,但实际上。通过制定大胆的策略,将复杂度的问题转换成复杂度的问题。 从react渲染开始: 在说react虚拟dom之前我们先来看看react渲染过程,下面链接是根据源码渲染过程写的简写版。http://1.sharemandy.sina...
摘要:前言月份开始出没社区,现在差不多月了,按照工作的说法,就是差不多过了三个月的试用期,准备转正了一般来说,差不多到了转正的时候,会进行总结或者分享会议那么今天我就把看过的一些学习资源主要是博客,博文推荐分享给大家。 1.前言 6月份开始出没社区,现在差不多9月了,按照工作的说法,就是差不多过了三个月的试用期,准备转正了!一般来说,差不多到了转正的时候,会进行总结或者分享会议!那么今天我就...
阅读 1647·2021-10-29 13:11
阅读 785·2021-09-22 10:02
阅读 1666·2021-08-20 09:35
阅读 1537·2019-08-30 15:54
阅读 2439·2019-08-30 15:44
阅读 1349·2019-08-29 16:52
阅读 1073·2019-08-23 12:56
阅读 735·2019-08-22 15:16