翻译的一个React文章,然后发现翻译不容易…
下面是非常不完整且用词可能不恰当的部分内容
附上个原文链接:
Complete Intro React
React基础知识
渲染一个元素的方式
//DOM API
document.getElementById('mountNode').innerHTML = `
<div>
Hello HTML
</div>
`;
//reacts API
ReactDOM.render(
React.createElement(
'div',
null,
'Hello React',
),
document.getElementById('mountNode2'),
);
//区别:Dom API 可以以模板字符串的形式构建dom树,而React API通过JS添加React元素作为参数,以对象的形式构建DOM树
ReactAPI的优势:
React API创建元素的方式看起来比DOM API更复杂,且呈与DOM API呈现的初次渲染的效果是一致,那么我们为什么还要使用它呢?
React的优势不是首次渲染时,而是在更新视图中显现的,它只会更新依赖变动数据的DOM节点,而DOM API发生数据变动时会不断刷新整个DOM节点
上述例子所用到的React方法
- 关于ReactDom.render(arg1,arg2)方法:
这是React元素渲染成DOM节点的入口
arg1:渲染在浏览器上的内容–通常是一个React元素
agr2:React元素即将渲染的位置,必须为html中存在的真实节点 - 关于React.createElement(arg1,arg2,arg3)
arg1:第一个参数是一个html标签,作为根元素
arg2:第二个参数是标签所具有的属性(href ,src, id, title ,etc)
arg3:第三个是所创建的根元素的内容,可选,根元素可具有0个或多个孩子节点。
React-以组件的形式发挥作用
组件—可以看作函数 一个大组件----可由多个小组件构成
使用函数创建组件
function Button (props) {
// Returns a DOM/React element here. For example:
return <button type="submit">{props.label}</button>;
}
// To render a Button element in the browser
ReactDOM.render(<Button label="Save" />, mountNode);
上述代码return中的语句:既不是HTML也不是JS,而是属于JSX的语法:是JS的扩展,允许我们以HTML语法的形式写函数
浏览器无法理解JSX语法。只能理解JSX背后的React API,但是JSX可以帮助我们直接使用类似HTML的语法,而不必全部使用JS,Babel或TypeScript之类的编译器可以将JSX转化为React语法
//浏览器上运行报错
function Button (props) {
// Returns a DOM/React element here. For example:
return <button type="submit">{props.label}</button>;
}
//浏览器上运行不报错
function Button (props) {
return React.createElement(
"button",
{ type: "submit" },
props.label
);
}
ReactDOM.render(
React.createElement(Button, { label: "Save"}),
mountNode
);
因此一个React组件实质上是一个JS函数,通过JSX返回React元素,React元素由调用React API创建,即返回创建React元素(本质上是JavaScript对象)的函数调用。
区分函数React组件html标签
自定义的React 组件首字母必须要大写,否则JSX编译器会将其视为普通的html元素,而普通元素是作为字符串传递给React.createElement调用的,而React组件则是以变量的形式传递
使用函数组件
function Button (props) {
return React.createElement(
"button",
{ type: "submit" },
props.label
);
}
ReactDOM.render(
React.createElement(Button, { label: "Save"}),
mountNode
);
props:表示react组件所接收到的属性列表,是一个对象{name:value},接受到的属性列表对象均标准命名为props,参数是可选的
一个组件可能没有传递的参数,但是组件必须具有返回值,不能返回“undefind”,当返回值为null时,render函数执行时会对其忽略
const Button = ({ label }) => (
<button type="submit">{label}</button>
);
可使用ES6的语法对接收到的属性进行解构赋值,该方法可以选择只接受需要用的属性,忽略无关的额外属性
你可以在JSX中的大括号{}内使用JS表达式,举个例子,在JSX中不能使用正则,或者if else语句,但是三元运算符作为JS表达式是被允许的,当返回的是值时都可以在JSX中使用,譬如{}中包含一个函数调用,该函数里可以放任何内容进行返回。JS变量也是表达式,所以接收到的参数可以在JSX中显示
JS对象也可作为表达式在JSX中使用,如下面的例子
class ConditionalStyle extends React.Component {
render() {
return (
<div style={{ color: Math.random() < 0.5 ? 'green': 'red' }}>
How do you like this?
</div>
);
}
}
ReactDOM.render(
<ConditionalStyle />,
mountNode,
);
使用该方式比通过判断条件使用那个类名,然后在全局CSS样式表中追踪类名更简单
模板语言是指使用JS将该语法转换成DOM操作。Dom操作可以在浏览器中使用展示DOM树,但JSX不是模板语言,它不必进行这一步,我们传递的是React API生成的对象树,react直接使用这些对象去生成可呈现DOM树的DOM操作,如当一个HTML模板语言被使用的时候,这些应用会被看作是一个字符串,而一个React 应用则是被视为一个对象。
JSX只是看起来想一个模板语言,但它确实不是,它只是JS的扩展,允许我们以一种近似html的语法去呈现React对象树,浏览器和React都不必处理JSX,只有编译器可以,传送给浏览器的是不含JSX和模板字符串的代码
使用类组件
一个类组件必须定义一个render方法,该render方法需要返回React元素,每当我们使用react组件的时候,React将实例化该组件中的对象,并使用该对象去创建DOM元素,还将DOM元素与实例化的类相关联。
class Button extends React.Component {
render() {
return (
<button>{this.props.label}</button>
);
v }
}
// Use it (same syntax)
ReactDOM.render(<Button label="Save" />, mountNode);
注意类组件JSX中的参数props,每一个组件都有一个名为props中的实例属性对象,该属性保留实例化时传递给该组件的所有属性,与函数组件不同,render函数在类组件中并不会接受任何参数
函数组件与类组件的区别
类组件是有状态的
函数组件无状态
组件和元素的区别
React Component是一个模板,是一个全局的定义,可以是一个函数或者是带有render方法的类
React Element是从组件中返回的内容,它是由组件呈现的一个描述DOM节点的虚拟的对象,在函数组件中,react元素是这个函数返回的一个对象,在类组件中的render函数返回的对象。
ReactDOM中渲染多个组件
//错误写法
ReactDOM.render(<Button /><Display />, mountNode);
//正确写法1
ReactDOM.render([<Button />, <Display />], mountNode);
//正确写法2
ReactDOM.render(
<div>
<Button />
<Display />
</div>,
mountNode
);
//最佳写法:使用fragment可以无需引进父节点
ReactDOM.render(
<React.Fragment>
<Button />
<Display />
</React.Fragment>,
mountNode
);
ReactDOM.render(
<>
<Button />
<Display />
</>,
mountNode
);
关于顶层组件
我们可以将动态数据以及处理数据的方法提取到顶层组件中,通过props传递给子组件,子组件触发事件时调用的顶层组件中定义的方法,使用顶层组件通常用于管理共享的应用程序状态和操作,因为它是所有组件的父级,设计顶层组件时需要谨慎,因为在顶层组件中更新一个有状态的元素意味着会重新渲染整个组件树(在内存中)
状态抽取到顶层组件中的例子:
import React, { useState } from 'react';
const Button = ({ clickAction }) => {
return (
<button onClick={clickAction}>
+1
</button>
);
};
const Display = ({ content }) => (
<pre>{content}</pre>
);
const CountManager = () => {
const [count, setCount] = useState(0);
const incrementCounter = () => {
setCount(count + 1);
};
return (
<div>
<Button clickAction={incrementCounter} />
<Display content={count} />
</div>
);
};
注意:在React中不能将number作为字符串的形式传递
生命周期函数作用
第一次渲染React组件在浏览器中的阶段被称为mounting
从浏览器中移除组件的阶段被称为“unmounting”
处于mounting undating unmounting时期的组件都有一个双面的影响(副作用),需要React API和DOM API的结合使用,而副作用通常发生在React组件渲染之前或者之后,所以React在类组件中提供生命周期函数,使组件在渲染之前或之后可以使用原始方法。
componentDidMount componentDidUpdate componentWillUnmount
我们可以在类组件提供的这些周期方法中进行一些操作
对函数组件,这些副作用使用 React.useEffect 钩子函数进行管理
useEffect(() => {
// Do something after each render
// but only if dep1 or dep2 changed
}, [dep1, dep2]);
React函数组件第一次渲染完成后会有一个useEffect的回调方法,每一次重新渲染时,如果依赖的值与上次渲染的值是不同的,React也将调用这个回调函数
React函数组件更新或者卸载时,react会调用“cleanup”的回调方法,cleanup函数可以从useEffect回调函数中返回。