元素渲染

更新元素渲染

计时器例子

function tick(){
const element = (
<div>
<h1>Hello, World!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
); ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(tick, 1000)

react只会更新必要的部分,上面计时器的例子中,只会更新时间,而element中的Hello, World等则不会更新。

组建 & Props

自定义组件

自定义组件包括函数定义组件和类定义组件,下面例子中两种定义的效果是相同的。

// 函数定义组件
// function Welcome(props){
// return <h1>Hello, {props.name}</h1>;
// } // 类定义组件
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
} const element = <Welcome name="Sarah" />; ReactDOM.render(
element,
document.getElementById('root')
);

组合组件

组件可以在返回值中引用其它组件,从而实现组件之间的组合。

// 类定义组件
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
} class App extends React.Component {
render(){
return (
<div>
<Welcome name='Sarah' />
<Welcome name='Lily' />
<Welcome name='Dency' />
</div>
);
}
} ReactDOM.render(
<App />,
document.getElementById('root')
);

提取组件

通过提取组件可以将一个大的组件拆分成由许多小的组件合并而成。

原始组件:

function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avater"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-data">
{formatData(props.date)}
</div>
</div>
);
}

拆分后:

// Avater组件
function Avater(props) {
return (
<img className="Avater"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
// UserInfo组件
function UserInfo(props) {
return (
<div className="UserInfo">
<Avater user={props.author} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
);
}
// 修改后的Comment
function Comment(props) {
return (
<div className="Comment">
<UserInfo author={props.author} />
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-data">
{formatData(props.date)}
</div>
</div>
);
}

Props只能用来读取,不能被修改。

State & 生命周期

生命周期

用组件的生命周期改写上面的计时器功能

class Clock extends React.Component{
constructor(props) {
super(props);
this.state = {date: new Date()};
} // 组件插入到DOM中启动定时器
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
} // 组件移出DOM时去除定时器
componentWillMount() {
clearInterval(this.timerID);
} tick(){
this.setState({
date: new Date()
});
} render(){
return (
<div>
<h1>Hello, World!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
} ReactDOM.render(
<Clock />,
document.getElementById('root')
);

正确使用状态

不可直接更新状态

以下代码不会重新渲染组件

this.state.comment = "Hello"

应当使用setState

状态更新可能是异步的

React可以将多个setState()调用合并成一个调用来提高性能。所以状态更新是异步的,不能根据上一个状态值来计算下一个状态值。

// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
// Correct
this.setState(function(prevState, props) {
return (
counter: prevState.counter + props.increment
);
});

事件处理

React事件绑定属性命名采用驼峰写法,需要传入一个事件处理函数,而不是一个字符串。

// HTML
<button onclick="activateLasers()">
Activate Lasers
</button>
// React
<button onClick={activateLasers}>
Activate Lasers
</button>

在React中不能使用返回false的方式阻止默认行为,而要使用preventDefault。

// HTML
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}

使用this绑定点击事件

class Toggle extends React.Component {
constructor(props){
super(props);
this.state = {
isToggleOn: true
};
// This blinding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
} handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
} render(){
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
} ReactDOM.render(
<Toggle />,
document.getElementById('root')
);

使用如下两种写法可以不用使用bind绑定this

  handleClick = () => {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
  render(){
return (
<button onClick={(e) => this.handleClick(e)}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}

向事件处理程序传递参数

有两种方式可以向事件处理程序传递参数

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deletdRow.bind(this, id)}>Delete Row</button>

下面例子使用bind()传递参数

class Popper extends React.Component{
constructor(){
super();
this.state = {name:'Hello world'};
} preventPop(name, e){ // 事件对象e要放在最后
e.preventDefault();
alert(name);
} render(){
return (
<div>
<p>hello</p>
{/* Pass params via bind() method. */}
<a href="http://reactjs.org" onClick={this.preventPop.bind(this, this.state.name)}>Click</a>
</div>
);
}
} ReactDOM.render(
<Popper />,
document.getElementById('root')
);

条件渲染

与运算符 &&

function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread message.
</h2>
}
</div>
);
} const message = ['React', 'Re: React', 'Re:Re: React'] ReactDOM.render(
<Mailbox unreadMessages={message} />,
document.getElementById('root')
);

在JavaScript中,true && expression 总是返回expression,而 false && expression 总是返回false。

阻止组件渲染

function WarningBanner(props) {
if(!props.warn) {
return null;
} return (
<div className="warning">
Warning!
</div>
);
} class Page extends React.Component {
constructor(props) {
super(props);
this.state = {showWarning: true}
this.handleToggleClick = this.handleToggleClick.bind(this);
} handleToggleClick() {
this.setState(prevState => ({
showWarning: !prevState.showWarning
}));
} render() {
return (
<div>
<WarningBanner warn={this.state.showWarning} />
<button onClick={this.handleToggleClick}>
{this.state.showWarning ? 'Hide' : 'Show'}
</button>
</div>
);
}
} ReactDOM.render(
<Page />,
document.getElementById('root')
);

列表 & Keys

渲染多个组件

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
); ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);

基础列表组件

function NumberList(props) {
const number = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
} const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);

注意,如果不加key属性,会得到一个警告 a key should be provided for list items。意思是每个列表元素都应该分配一个确定的标识。

Keys

一个元素的key最好是这个元素在列表中拥有的独一无二的字符串。通常我们使用来自数据的id作为元素的key。

const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);

当元素没有确定的id时,可以使用它的序列号索引index作为key

const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);

元素的key在他的兄弟元素之间应该唯一,但是不需要全局唯一,也就是说不同列表的元素可以使用相同的key。

key会作为React的提示,但是不会传递给组件。如果组件中需要使用和key相同的值,可将其作为属性传递:

// Post组件可以读出props.id, 但是不能读出props.key
const content = posts.map((post) =>
<Post
key={post.id}
id={post.id}
title={post.title}
/>
);

表单

select

class FlavorForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: 'coconut' }; this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
} handleChange(event) {
this.setState({value: event.target.value});
} handleSubmit(event) {
alert('Your favorite flavor is: ' + this.state.value);
event.preventDefault();
} render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Pick your favorite La Croix flavor:
<select value={this.state.value} onChange={this.handleChange}>
<option value="grapefruit">grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
<input type="submit" value="submit" />
</form>
);
}
} ReactDOM.render(
<FlavorForm />,
document.getElementById('root')
);

在React中并不使用之前的selected属性,而是在根select标签上用value来表示选中项。

多个输入

class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
}; this.handleInputChange = this.handleInputChange.bind(this);
} handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name; this.setState({
[name]: value
});
} render() {
return (
<form>
<label>
Is going:
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange}
/>
</label>
<br />
<label>
Number of Guests:
<input
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
</form>
);
}
} ReactDOM.render(
<Reservation />,
document.getElementById('root')
);

上面通过给元素一个name属性,让函数根据event.target.name的值来选择做什么,这样就可以在一个处理函数中处理多个input元素。

状态提升

状态提升是指多个组件共用一个值时,每次改变值时不进行双向绑定,而是将该值提升到上一级的共同组件中。

组合 VS 继承

包含关系

使用children属性将子元素直接传递到输出。

function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
} function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
} ReactDOM.render(
<WelcomeDialog />,
document.getElementById('root')
);

除此之外,也可以使用自己约定的属性,在组件中需要多个入口的情况下非常有用。

function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
} function App() {
return (
<SplitPane left={<Contacts />} right={<Chat />} />
);
} ReactDOM.render(
<App />,
document.getElementById('root')
);

特殊实例

一个组件可以是另一个组件的实例。

function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
} function Dialog(props) {
return(
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
</FancyBorder>
);
} function WelcomeDialog() {
return (
<Dialog
title="Welcome"
message="Thakn you for visiting our spacecraft!"
/>
);
} ReactDOM.render(
<WelcomeDialog />,
document.getElementById('root')
);

组合对于定义类的组件同样适用。

function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
} function Dialog(props) {
return(
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
</FancyBorder>
);
} class SignUpDialog extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSignUp = this.handleSignUp.bind(this);
this.state = {login: ''};
} render() {
return (
<Dialog title="Mars Exploration Program"
message="How should we refer to you?">
<input value={this.state.login} onChange={this.handleChange} />
<button onClick={this.handleSignUp}>
Sign Me Up!
</button>
</Dialog>
);
} handleChange(e) {
this,this.setState({login: e.target.value});
} handleSignUp() {
alert(`Welcome aboard, ${this.state.login}!`);
}
} ReactDOM.render(
<SignUpDialog />,
document.getElementById('root')
);

React文档总结的更多相关文章

  1. React文档(十三)思考React

    在我们的看来,React是使用js创建大型快速网站应用的首要方法.它在Facebook和Instagram的使用已经为我们展现了它自己. React的一个很好的地方就在于当你创建应用的时候它使你思考如 ...

  2. React文档(二十四)高阶组件

    高阶组件(HOC)是React里的高级技术为了应对重用组件的逻辑.HOCs本质上不是React API的一部分.它是从React的组合性质中显露出来的模式. 具体来说,一个高阶组件就是一个获取一个组件 ...

  3. react文档demo实现输入展示搜索结果列表

    文档页面地址:https://doc.react-china.org/docs/thinking-in-react.html 该文档只给了具体实现思路,下面是我实现的代码. 初学react,如果有写的 ...

  4. React文档(一)安装

    React是一个灵活的可以用于各种不同项目的框架,你可以用它来写新应用,你也可以逐步将它引进已有的代码库而不用重写整个项目. 试用React 如果你想玩一玩React,那么就去CodePen上试一试. ...

  5. React文档(十六)refs和DOM

    Refs 提供了一种方式,用于访问在 render 方法中创建的 DOM 节点或 React 元素. 在标准的React数据流中,props是使得父组件和子组件之间交互的唯一方式.你通过props重新 ...

  6. React文档(二十三)Web Components

    React和web components是为了解决不同问题而创立的.web components为可重用组件提供了健壮的封装,而React提供了声明式的库来保持DOM和数据同步.这两点是互相补充的.作 ...

  7. React文档(二十二)context

    React中,通过React组件可以很容易地追踪数据流.当你关注一个组件,你可以发现哪一个props被传递了,这样使得你的应用很容被推断. 在一些情况下,你想要传递数据通过组件树而不需要去手动在每一层 ...

  8. React文档(二十一)协调

    React提供了一个声明式地API因此你不用担心每一次更新什么东西改变了.这使得开发应用变得简单,但是这个东西在React中如何实现的并不是很明显.这篇文章会解释我们在React的算法中所做的选择以便 ...

  9. React文档(二十)不使用JSX

    JSX并不是使用React的一个强制需求.当你不需要在你的构造环境里设置编译那么不使用JSX会很方便. 每一个JSX元素只是调用React.createElement(componnet, props ...

  10. React文档(十九)不使用ES6

    通常你会将一个React组件定义成一个普通的js类: class Greeting extends React.Component { render() { return <h1>Hell ...

随机推荐

  1. BZOJ2824 AHOI2012 铁盘整理 【IDA*】

    BZOJ2824 AHOI2012 铁盘整理 Description 在训练中,一些臂力训练器材是少不了的,小龙在练习的时候发现举重器械上的铁盘放置的非常混乱,并没有按照从轻到重的顺序摆放,这样非常不 ...

  2. Lua table

    获取数组长度 在Lua中可以使用“#”和table.maxn两种方法来获取数组的长度 arr = {,,,} arr[] = 7 都仅统计数字key的长度: #是从1递增到nil的长度: table. ...

  3. 揭示同步块索引(中):如何获得对象的HashCode

    转自:http://www.cnblogs.com/yuyijq/archive/2009/08/13/1545617.html 题外话:为了尝鲜,也兴冲冲的安装了Win7,不过兴奋之余却郁闷不已,由 ...

  4. Clairewd’s message(哈希模板+)

    个人心得:一开始就是知道用哈希,但是无从下手,很明显是对哈希不太了解和思维不太好. 先来看一下这一题涉及到的哈希吧和这题的思路吧,思路就是对所给的密文用原文和翻译后进行hash处理,那么必然存在后面那 ...

  5. psoc做dds

    今天用psoc做了dds,现在总结一下. 1dds用到的相位累加器是用verilog写的,本来准备用一下datapath,这是和fpga不一样的一点,用了类似alu的结构,但是看手册后发现,虽然可以执 ...

  6. mac版sublime 无法下载插件(Vue 代码无高亮问题)

    1.官方下载sublime(http://www.sublimetext.com/3) 然后需要两步(1)上传插件主包Package Control(2)更改channels的配置信息(原来是国外的需 ...

  7. filter敏感词替换

    1.properties文件的应用 在<filter>写入配置 <filter> <filter-name>myFilter</filter-name> ...

  8. Unit03: Spring Web MVC简介 、 基于XML配置的MVC应用 、 基于注解配置的MVC应用

    Unit03: Spring Web MVC简介 . 基于XML配置的MVC应用 . 基于注解配置的MVC应用 springmvc (1)springmvc是什么? 是一个mvc框架,用来简化基于mv ...

  9. 配置Jar包及相关依赖Jar包的本地存放路径

    配置Jar包及相关依赖Jar包的本地存放路径 用 maven2 ,pom.xml中设置了依赖,会帮你下载所有依赖的.jar到 M2_REPO 指向的目录. M2_REPO是一个用来定义 maven 2 ...

  10. JFreeChart API 说明(转)

    原地址 http://blog.csdn.net/mike_caoyong/article/details/7338160 JFreeChart目前是最好的java图形解决方案,基本能够解决目前的图形 ...