1.All the fundamental React.js concepts, jammed into this single Medium article
这篇简单Medium文章包含了所有基本的react.js概念(下面代码都摘自原文 详细了解请阅读原文)
基本概念#1:React就是组件 (React is all about components)
React是围绕可复用组件(resuable components)的概念设计的。你可以定义小组件然后组合成更大的组件。即使在不同项目中,所有大型或者小型的组件都可以重复使用。一个react组件-最简单的形式-就是一个简单javaScript函数(a plain-old javaScript function)
// 例子 1
// https://jscomplete.com/repl?j=Sy3QAdKHW
function Button (props){
//如:return 一个 dom 元素
return <button type ="submit">{props.lable}</button>
}
//将Button组件在浏览器中渲染
ReactDOM.render(<Button label = "save" />, mountNode)
请注意下面关于例子1:
- 组件的名字要以大写字母开头。这一要求是为了在混合使用HTML元素跟React元素时,区分它们。
- 每一个组件可以有属性列表,就像跟HTML元素一样。在react中,这个列表的名字称为props。
- 我们看到上面Button组件的返回输出值看起来像HTML的形式。它既不javaSCript也不是HTML,甚至不是react.js。但是,它很受欢迎,成为了react应用程序的默认设置。它叫做JSX,是javascript的扩展。
基本概念#2:JSX的变化是什么(What the flux is JSX)
下面是例子1不用JSX语法:
// 例子 2 -
// https://jscomplete.com/repl?j=HyiEwoYB-
function Button (props) {
return React.createElement(
"button",
{ type: "submit" },
props.label
);
}
//
ReactDOM.render(
React.createElement(Button, { label: "Save" }),
mountNode
);
createElement是react 中的API,creactElement 实际上就是创建树
// 例子 3
// https://jscomplete.com/repl?j=r1GNoiFBb
const InputForm = React.createElement(
"form",
{ target: "_blank", action: "https://google.com/search" },
React.createElement("div", null, "Enter input and click Search"),
React.createElement("input", { name: "q", className: "input" }),
React.createElement(Button, { label: "Search" })
);
// InputForm
function Button (props) {
return React.createElement(
"button",
{ type: "submit" },
props.label
);
}
//
ReactDOM.render(InputForm, mountNode);
请注意以下几点:
InputForm不是react组件,它是react元素。这是为什么我们在ReactDOM.render的时候直接使用,而没有使用<InputForm />形式React.createElement函数在第一第二参数之后接受多个参数。 从第三个开始参数列表是包含创建子元素的- 当元素不需要任何属性或者props的时候,
React.createElement的第二个参数可以是null 或者空对象 - 我们可以将HTML元素和React元素混合使用
- React API 尝试尽可能的接近DOM API
我们习惯看或者写HTML形式,所以采用接近HTML的语法形式 JSX
// 例子 4 - JSX (跟例3 比较)
// https://jscomplete.com/repl?j=SJWy3otHW
const InputForm =
<form target="_blank" action="https://google.com/search">
<div>Enter input and click Search</div>
<input name="q" className="input" />
<Button label="Search" />
</form>;
function Button (props) {
// Returns a DOM element here. For example:
return <button type="submit">{props.label}</button>;
}
//
ReactDOM.render(InputForm, mountNode);
请注意以下几点:
- 这不是HTML,比如这里是用
className代替class - 考虑将上面看似HTML的形式看作javascript,可以看到在最后添加了分号
上面写的例4形式是JSX,而浏览器看到的相当于它的编译版本例3。所以,我们需要预处理器(pre-processor)将就JSX版本的转换成React.createElement
顺便说一句,JSX可以单独使用,它不是 React-only
基本概念#3:可以在JSX中任何地方使用javaScipt表达式
在JSX中,你可以使用任何javaScript表达式,用一对花括号(curly braces)包围
// 例5
// https://jscomplete.com/repl?j=SkNN3oYSW
const RandomValue = () =>
<div>
{ Math.floor(Math.random() * 100) }
</div>;
//
ReactDOM.render(<RandomValue />, mountNode);
在花括号内,写入任何javaScript表达式,这种形式类似于 javaScript的模板语法${}
JSX 的唯一约束就是: 只能是表达式。因此,我们不能使用常规的if语句,需要使用三目表达式(ternary expression)
javaScript 变量(variable)也是表达式(expression),所以组件接收的props ,需要放在 花括号中
javaScript 对象也是表达式。有时我们在花括号内使用javaScript对象,这使它看起来像花括号,但其实它是花括号内写入的对象。一个例子就是在React中我们将CSS样式对象传递给style属性
// 列6
// https://jscomplete.com/repl?j=S1Kw2sFHb
const ErrorDisplay = ({message}) =>
<div style={ { color: 'red', backgroundColor: 'yellow' } }>
{message}
</div>;
ReactDOM.render(
<ErrorDisplay
message="These aren't the droids you're looking for"
/>,
mountNode
);
在jSX也可以使用React元素,因为这个它也是一个表达。请记住React元素本质上是函数调用
// 例7 - 在 {}使用 react元素
// https://jscomplete.com/repl?j=SkTLpjYr-
const MaybeError = ({errorMessage}) =>
<div>
{errorMessage && <ErrorDisplay message={errorMessage} />}
</div>;
const ErrorDisplay = ({message}) =>
<div style={ { color: 'red', backgroundColor: 'yellow' } }>
{message}
</div>;
ReactDOM.render(
<MaybeError
errorMessage={Math.random() > 0.5 ? 'Not good' : ''}
/>,
mountNode
);
你也可以在JSX中使用javaScript的集合(collection)方法(map,reduce,filter,concat,等等),因为它们返回的也是表达式
// 例8- 在 {}使用 数组map
// https://jscomplete.com/repl?j=SJ29aiYH-
const Doubler = ({value=[1, 2, 3]}) =>
<div>
{value.map(e => e * 2)}
</div>;
ReactDOM.render(<Doubler />, mountNode);
基本概念#4:你可以用class 来写React 组件
// Example 9 - 使用class写react组件
// https://jscomplete.com/repl?j=ryjk0iKHb
class Button extends React.Component {
render() {
return <button>{this.props.label}</button>;
}
}
ReactDOM.render(<Button label="Save" />, mountNode);
// 例 10 -
// https://jscomplete.com/repl?j=rko7RsKS-
class Button extends React.Component {
constructor(props) {
super(props);
this.id = Date.now();
}
render() {
return <button id={this.id}>{this.props.label}</button>;
}
}
ReactDOM.render(<Button label="Save" />, mountNode);
// 例 11
// https://jscomplete.com/repl?j=H1YDCoFSb
class Button extends React.Component {
clickCounter = 0;
handleClick = () => {
console.log(`Clicked: ${++this.clickCounter}`);
};
render() {
return (
<button id={this.id} onClick={this.handleClick}>
{this.props.label}
</button>
);
}
}
// Use it
ReactDOM.render(<Button label="Save" />, mountNode);
基本概念#5:React事件:两个重要的差异
// 例 12
// https://jscomplete.com/repl?j=HkIhRoKBb
class Form extends React.Component {
handleSubmit = (event) => {
event.preventDefault();
console.log('Form submitted');
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
}
ReactDOM.render(<Form />, mountNode);
基本概念#6: ( Every React component has a story)
基本概念#7: React组件有私有状态
// 例子 13 -
// https://jscomplete.com/repl?j=H1fek2KH-
class CounterButton extends React.Component {
state = {
clickCounter: 0,
currentTimestamp: new Date(),
};
handleClick = () => {
this.setState((prevState) => {
return { clickCounter: prevState.clickCounter + 1 };
});
};
componentDidMount() {
setInterval(() => {
this.setState({ currentTimestamp: new Date() })
}, 1000);
}
render() {
return (
<div>
<button onClick={this.handleClick}>Click</button>
<p>Clicked: {this.state.clickCounter}</p>
<p>Time: {this.state.currentTimestamp.toLocaleString()}</p>
</div>
);
}
}
ReactDOM.render(<CounterButton />, mountNode);