React 入门

React 背景知识

React 是一个用于构建用户界面的 JavaScript 库,主要用于构建 UI,而不是一个 MVC 框架,但可以使用 React 作为 MVC 架构的 View 层轻易的在已有项目中使用,它是一个用于构建用户界面的 JavaScript 库,起源于 Facebook 的内部项目,用来架设 Instagram 的网站,于 2013 年 5 月开源。

React 特点

  • 1.声明式设计 −React采用声明范式,可以轻松描述应用。

  • 2.高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。

  • 3.灵活 −React可以与已知的库或框架很好地配合。

  • 4.JSX − JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但我们建议使用它。

  • 5.组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。

  • 6.单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。

环境准备

方式一:在浏览器中编写代码

  • 直接在浏览器选项卡中使用codepen编写

方法二:直接使用 Staticfile CDNReact CDN

  • 直接使用 Staticfile CDN 的 React CDN 库,地址如下:
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
  • 官方提供的 CDN 地址:
<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.15.0/babel.min.js"></script>
  • 使用实例如下,直接打开index.html页面会输出 Hello, world!:
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>Hello React!</title>
    <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
    <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>

<div id="example"></div>
<script type="text/babel">
	ReactDOM.render(
		<h1>Hello, world!</h1>,
		document.getElementById('example')
	);
</script>

</body>
</html>

方式三:搭建本地开发环境,通过 npm 使用 React

  • 环境要求: Node>= 10.16 和 npm >= 5.6

  • 使用 create-react-app 快速构建 React 开发环境

    $ cnpm install -g create-react-app
    $ create-react-app my-app
    $ cd my-app/
    $ npm start   // 运行本地服务
    

在浏览器中打开 http://localhost:3000/ 就能看到运行结果。

  • 项目的目录结构如下:
my-app/
  README.md
  node_modules/
  package.json
  .gitignore
  public/
    favicon.ico
    index.html
    manifest.json
  src/
    App.css
    App.js
    App.test.js
    index.css
    index.js
    logo.svg

manifest.json 指定了开始页面 index.html,一切的开始都从这里开始,所以这个是代码执行的源头。

React 元素渲染

ReactDOM.render()

ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('example')
);

上面代码将一个 h1 标题,插入 example 节点.

将元素渲染到 DOM 中

首先我们在一个 HTML 页面中添加一个 id=“example” 的,如下:

<div id="example"></div>

React 开发应用时一般只会定义一个根节点。

要将React元素渲染到根DOM节点中,我们通过把它们都传递给 ReactDOM.render() 的方法来将其渲染到页面上:

const element = <h1>Hello, world!</h1>;
ReactDOM.render(
    element,
    document.getElementById('example')
);

更新元素渲染

React 元素都是不可变的。当元素被创建之后,你是无法改变其内容或属性的。

目前更新界面的唯一办法是创建一个新的元素,然后将它传入 ReactDOM.render() 方法,比如下面这个定时器:

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>现在是 {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(
    element,
    document.getElementById('example')
  );
}
 
setInterval(tick, 1000);

ReactDOM.render调用函数及参数传递

  • ReactDOM.render内调用 已有函数与常规的JS有很大的区别:
    • 函数引用直接包含在</>中,而不是()
    • 多个参数是以key、value时直接传递的,而不是对象格式的date数据
    • 示例如下:
 ReactDOM.render(
      < functionname  property1 = {property1_value}  property2 = {property2_value} />,
       document.getElementById('example')
   );

以下实例用一个函数来表示前面的定时器封装:

function Clock(props){
    return (
        <div id={props.id}>
            <h1>Hello, {props.name} ~</h1>
            <h2>现在是北京时间 {props.date.toLocaleTimeString()}</h2>
        </div>
    )
}

function tick() {
    ReactDOM.render(
        < Clock date={new Date()} name={'world'} id={'world'}/>,
        document.getElementById('example')
    );
}

setInterval(tick, 1000);

值得注意的是 React DOM 首先会比较元素内容先后的不同,而在渲染过程中只会更新改变了的部分。

创建React.Component 的 ES6 类

需要注意的是在 render() 方法中,需要使用this.props 替换 props,示例:

class Clock extends React.Component{
    render(){
        return(
            <div id={this.props.id}>
                <h1>Hello, {this.props.name} ~</h1>
                <h2>现在是北京时间 {this.props.date.toLocaleTimeString()}</h2>
            </div>
        )
    }
}

function tick() {
    ReactDOM.render(
        < Clock date={new Date()} name='world' id='world'/>,
        {/* new Date() 这样的value,需要使用花括号来包含,仅字符串的值则不需要 */}
        document.getElementById('example')
    );
}

setInterval(tick, 1000);

React JSX

js和jsx的区别

既然这里提到了jsx,那就顺便了解一下两者的区别:

  • JS:即JavaScript,一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于浏览器客户端的脚本语言。
  • JSX: 即JavaScript XML——一种在React组建内部构建标签的类XML语法。(增强React程序组件的可读性)。Javascript和XML结合的一种格式。React发明了JSX,利用HTML语法来创建虚拟DOM。当遇到<,JSX就当HTML解析,遇到{就当JavaScript解析。

使用 jsx

React 实例

ReactDOM.render(
    <div>
	    <h1>React JSX</h1>
	    <h2>欢迎学习 React jsx</h2>
	    <p data-myattribute = "somevalue">这是一个很不错的 JavaScript 库!</p>
    </div>,
    document.getElementById('example')
);

jsx独立文件

  • 创建jsx独立文件:例如我们创建一个 helloworld_react.js 文件,代码如下:
ReactDOM.render(
	<h1>hello, world</h1>,
	document.getElementById('example')
)
  • 然后在 HTML 文件中引入该 JS 文件(注意:script type 为 text/babel):
<body>
  	<div id="example"></div>
	<script type="text/babel" src="helloworld_react.js"></script>
</body>

注意:script 标签的 type 属性为 text/babel 。这是因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel"

JavaScript 表达式

  • 在 JSX 中使用 JavaScript 表达式。表达式写在花括号 {} 中:
ReactDOM.render(
    <div>
      <h1>{1+1}</h1>
    </div>
    ,
    document.getElementById('example')
);
  • 条件判断语句:在 JSX 中不能使用 if else 语句,但可以使用 conditional (三元运算) 表达式来替代
ReactDOM.render(
 	<div>
      <h1>{i == 1 ? 'True!' : 'False'}</h1>
    </div>
    ,
    document.getElementById('example')
)

样式

React 推荐使用内联样式。我们可以使用 camelCase 小驼峰 语法来设置内联样式. React 会在指定元素数字后自动添加 px ,如font-size要写成fontSize:

let myStyle = {
	fontSize: 100,
	color: '#FF0000'
};
ReactDOM.render(
	<h1 style={myStyle}>hello, world {1+1}</h1>,
	document.getElementById('example')
)

注释

注释需要 写在花括号{} 中,实例如下:

ReactDOM.render(
	<h1>
		hello, world {1+1}
		{/*这是注释部分*/}
	</h1>,
	document.getElementById('example')
)

数组

JSX 允许在模板中插入数组,数组会自动展开所有成员:

let arr = [
	<h1>React教程</h1>,
	<h2>学的不仅是React,学的是方法。</h2>,
];
ReactDOM.render(
	<div>{arr}</div>,
	document.getElementById('example')
)

React 组件

  • 组件类的第一个字母必须大写,否则会报错

实例解析:

function HelloMessage(props) {
	return <h1 className={props.class}>Hello {props.name}!</h1>;
}

const element = <HelloMessage class='testClass' name="Runoob"/>;

ReactDOM.render(
	element,
	document.getElementById('example')
);

注意:

  • 原生 HTML 元素名以小写字母开头,而自定义的 React 类名以大写字母开头,比如 HelloMessage 不能写成 helloMessage。除此之外还需要注意组件类只能包含一个顶层标签,否则也会报错。
  • 在添加属性时, class 属性需要写成 className ,for 属性需要写成htmlFor,这是因为 class 和 for 是 JavaScript 的保留字

复合组件

直接看例子吧:

function Name(props){
	return <h1>网站名称:{props.name}</h1>
}

function Url(props){
	return <h1>网站地址:{props.url}</h1>
}

function Nickname(props){
	return <h1>网站小名:{props.nickname}</h1>
}

function App(){
	return (
		<div>
			<Name name='React 复合组件学习'/>
			<Url url='http://www.runoob.com'/>
			<Nickname nickname={'React'}/>
		</div>
	)
}

ReactDOM.render(
	<App/>,
	document.getElementById('example')
);

React.createClass方法

React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类

let HelloMessage = React.createClass({
	render: function (){
		return <h1>hello, {this.props.name}!</h1>
	}
})

ReactDOM.render(
	<HelloMessage name='chrou' />,
	document.getElementById('example')
);

注:react最新版本弃用了 React.createClass这个函数,可以使用15.x版本尝试。

React State(状态)

React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。

将生命周期方法添加到类中

在具有许多组件的应用程序中,在销毁时释放组件所占用的资源非常重要。

  • 挂载:每当 Clock 组件第一次加载到 DOM 中的时候,我们都想生成定时器,这在 React 中被称为挂载
  • 卸载:同样,每当 Clock 生成的这个 DOM 被移除的时候,我们也会想要清除定时器,这在 React 中被称为卸载

我们可以在组件类上声明特殊的方法,当组件挂载或卸载时,来运行一些代码:


class Clock extends React.Component {
	constructor(props) {
		super(props)
		this.state = {date: new Date()}
	}

	componentDidMount(){
		let _this = this;
		this.timerID = setInterval(function (){
			_this.tick()
		}, 1000)
	}

	componentWillUnmount() {
		clearInterval(this.timerID)
	}

	tick(){
		this.setState({
			date: new Date()
		})
	}

	render(){
		return(
			<div>
				<h1>Hello, world!</h1>
				<h2>现在是北京时间:{this.state.date.toLocaleTimeString()}</h2>
			</div>
		)
	}
}

ReactDOM.render(
	<Clock />,
	document.getElementById('example')
);

实例解析:

  • componentDidMount()componentWillUnmount() 方法被称作生命周期钩子。
  • 在组件输出到 DOM 后会执行 componentDidMount() 钩子,我们就可以在这个钩子上设置一个定时器。
  • 通过调用 setState(),React 知道状态已经改变,并再次调用 render() 方法来确定屏幕上应当显示什么。 这一次,render() 方法中的 this.state.date将不同,所以渲染输出将包含更新的时间,并相应地更新 DOM。
  • this.timerID 为定时器的 ID,我们可以在 componentWillUnmount()钩子中卸载定时器。

数据自顶向下流动

父组件或子组件都不能知道某个组件是有状态还是无状态,并且它们不应该关心某组件是被定义为一个函数还是一个类。
这就是为什么状态通常被称为局部或封装。 除了拥有并设置它的组件外,其它组件不可访问。
以下实例中 FormattedDate 组件将在其属性中接收到 date 值,并且不知道它是来自 Clock 状态、还是来自 Clock 的属性、亦或手工输入

function FormattedDate(props){
	return <h2>现在是北京时间:{props.date.toLocaleTimeString()}</h2>
}

class Clock extends React.Component {
	constructor(props) {
		super(props)
		this.state = {date: new Date()}
	}

	componentDidMount(){
		let _this = this;
		this.timerID = setInterval(function (){
			_this.tick()
		}, 1000)
	}

	componentWillUnmount() {
		clearInterval(this.timerID)
	}

	tick(){
		this.setState({
			date: new Date()
		})
	}

	render(){
		return(
			<div>
				<h1>Hello, world!</h1>
				<FormattedDate date={this.state.date}/>
			</div>
		)
	}
}

function App(){
	return(
		<div>
			<Clock />
			<Clock />
			<Clock />
		</div>
	)
}

ReactDOM.render(
	<App />,
	document.getElementById('example')
);

这里我还没有完全理解它的含义!

React Props

stateprops 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。

基本用法

前面的示例中都已经涉及到Props的使用,这里不再举例,只再提示一点普通类和ES6 class使用上的差别:

  • 普通的类:使用props.name 方式访问属性
  • ES6 类:使用this.props.name方式访问属性

State 和 Props

例:在父组件中设置 state, 并通过在子组件上使用 props 将其传递到子组件上。在 render 函数中, 我们设置 name 和 site 来获取父组件传递过来的数据

class Book extends React.Component{
	constructor(props) {
		super(props)

		this.state = {
			name: 'react',
			time: '2013年5月',
		}
	}

	render() {
		return (
			<div>
				<Name name={this.state.name}/>
				<Time time={this.state.time}/>
			</div>
		)
	}
}

class Name extends React.Component {
	render(){
		return(
			<h1>Book name: {this.props.name}</h1>
		)
	}
}

class Time extends React.Component {
	render(){
		return(
			<h1>Book create time: {this.props.time}</h1>
		)
	}
}

ReactDOM.render(
	<Book />,
	document.getElementById('example')
)

Props 验证

React.PropTypes 在 React v15.5 版本后已经移到了 prop-types 库。 React v15.5 版本以上使用时需要引入:<script src="https://cdn.staticfile.org/prop-types/15.6.1/prop-types.js"></script>

Props 验证使用 propTypes,它可以保证我们的应用组件被正确使用,React.PropTypes 提供很多验证器 (validator) 来验证传入数据是否有效。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。

React 16.4 实例:

var title = "react learner";
class MyTitle extends React.Component {
	render() {
		return (
			<h1>Hello, {this.props.title}</h1>
		);
	}
}

MyTitle.propTypes = {
	title: PropTypes.string
};
ReactDOM.render(
	<MyTitle title={title} />,
	document.getElementById('example')
);

更多验证器说明如下

MyComponent.propTypes = {
    // 可以声明 prop 为指定的 JS 基本数据类型,默认情况,这些数据是可选的
   optionalArray: React.PropTypes.array,
    optionalBool: React.PropTypes.bool,
    optionalFunc: React.PropTypes.func,
    optionalNumber: React.PropTypes.number,
    optionalObject: React.PropTypes.object,
    optionalString: React.PropTypes.string,
 
    // 可以被渲染的对象 numbers, strings, elements 或 array
    optionalNode: React.PropTypes.node,
 
    //  React 元素
    optionalElement: React.PropTypes.element,
 
    // 用 JS 的 instanceof 操作符声明 prop 为类的实例。
    optionalMessage: React.PropTypes.instanceOf(Message),
 
    // 用 enum 来限制 prop 只接受指定的值。
    optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
 
    // 可以是多个对象类型中的一个
    optionalUnion: React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.number,
      React.PropTypes.instanceOf(Message)
    ]),
 
    // 指定类型组成的数组
    optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
 
    // 指定类型的属性构成的对象
    optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
 
    // 特定 shape 参数的对象
    optionalObjectWithShape: React.PropTypes.shape({
      color: React.PropTypes.string,
      fontSize: React.PropTypes.number
    }),
 
    // 任意类型加上 `isRequired` 来使 prop 不可空。
    requiredFunc: React.PropTypes.func.isRequired,
 
    // 不可空的任意类型
    requiredAny: React.PropTypes.any.isRequired,
 
    // 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。
    customProp: function(props, propName, componentName) {
      if (!/matchme/.test(props[propName])) {
        return new Error('Validation failed!');
      }
    }
  }
}

React 事件处理

  • React 事件绑定属性的命名采用驼峰式写法,而不是小写。

    <button onClick={activateLasers}>激活按钮</button>
    
  • 在 React 中另一个不同是你不能使用返回 false 的方式阻止默认行为, 你必须明确使用 preventDefault

    function ActionLink() {
      function handleClick(e) {
        e.preventDefault();
        console.log('链接被点击');
      }
     
      return (
        <a href="#" onClick={handleClick}>
          点我
        </a>
      );
    }
    

向事件处理程序传递参数

通常我们会为事件处理程序传递额外的参数。例如,若是 id 是你要删除那一行的 id,以下两种方式都可以向事件处理程序传递参数:

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

通过 bind 方式向监听函数传参,在类组件中定义的监听函数,事件对象 e 要排在所传递参数的后面,例如:

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>
                {/* 通过 bind() 方法传递参数。 */}
                <a href="https://reactjs.org" onClick={this.preventPop.bind(this,this.state.name)}>Click</a>
            </div>
        );
    }
}
  • 补充:bind()是Function对象内建的方法,它们的第一个参数都是用来更改调用方法中this的指向

React 条件渲染

元素变量

添加元素变量帮助你有条件的渲染组件的一部分,而输出的其他部分不会更改。

function UserGreeting(props){
	return <h1>欢迎回来~</h1>
}

function GuestGreeting(props){
	return <h1>请先登录~</h1>
}

function Greeting(props){
	const isLogging = props.isLogging
	if(isLogging){
		return <UserGreeting />
	}
	return <GuestGreeting />
}

function LoginButton(props){
	return (
		<button onClick={props.onClick}>登录</button>
	)
}

function LogoutButton(props){
	return(
		<button onClick={props.onClick}>退出</button>
	)
}

class LoginControl extends React.Component {
	constructor(props) {
		super(props)
		this.handleLoginClick = this.handleLoginClick.bind(this)
		this.handleLogoutClick = this.handleLogoutClick.bind(this)
		this.state = {isLoggedIn: true}
	}

	handleLoginClick(){
		this.setState({isLoggedIn: true})
	}

	handleLogoutClick(){
		this.setState({isLoggedIn: false})
	}

	render(){
		let logged = this.state.isLoggedIn
		let button
		if(logged){
			button = <LogoutButton onClick={this.handleLoginClick} />
		}else {
			button = <LoginButton onClick={this.handleLogoutClick} />
		}

		return(
			<div>
				<Greeting isLogging={logged} />
				{button}
			</div>
		)
	}
}

ReactDOM.render(
	<LoginControl />,
	document.getElementById('example')
)

与运算符 &&

可以通过用花括号包裹代码在 JSX 中嵌入任何表达式 ,也包括 JavaScript 的逻辑与 &&,它可以方便地条件渲染一个元素。示例:

function MailBox(props){
	let unreadmessage = props.unreadmessage

	return(
		<div>
			<h1>Hello!</h1>
			{
				unreadmessage.length >0 && <h2>您有 {unreadmessage.length} 条未读消息。</h2>
			}
		</div>
	)
}

const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
	<MailBox unreadmessage={messages} />,
	document.getElementById('example')
);
  • 在 JavaScript 中,true && expression 总是返回 expression,而 false && expression 总是返回 false
  • 因此,如果条件是 true&& 右侧的元素就会被渲染,如果是false,React 会忽略并跳过它。

三目运算符

用法和 JavaScript 的条件运算符一样:

condition ? true : false。

示例:

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      )}
    </div>
  );
}

阻止组件渲染

实现:让 render 方法返回 null 而不是它的渲染结果即可实现。

function WarningBanner(props) {
	if (!props.warn) {
		return null;
	}

	return (
		<div className="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 ? '隐藏' : '显示'}
				</button>
			</div>
		);
	}
}

ReactDOM.render(
	<Page />,
	document.getElementById('example')
);

React 列表 & Keys

实例:使用 map() 方法遍历数组生成了一个 1 到 5 的数字列表(每个列表元素分配一个 key,不然会出现警告 a key should be provided for list items,意思就是需要包含 key:):

function NumberList(props) {
	const numbers = props.numbers;
	const listItems = numbers.map(function (item){
		return <li key={item.toString()}>{item}</li>
	});
	return (
		<ul>{listItems}</ul>
	);
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
	<NumberList numbers={numbers} />,
	document.getElementById('example')
);

Keys

  • 用途:在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化
  • 值:一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串

用keys提取组件

  • 元素的 key 只有在它和它的兄弟节点对比时才有意义。
function ListItem(props) {
  // 对啦!这里不需要指定key:
  return <li>{props.value}</li>;
}
 
function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // 又对啦!key应该在数组的上下文中被指定
    <ListItem key={number.toString()}
              value={number} />
 
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}
 
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('example')
);

元素的 key 在他的兄弟元素之间应该唯一

  • 数组元素中使用的 key 在其兄弟之间应该是独一无二的。然而,它们不需要是全局唯一的。当我们生成两个不同的数组时,我们可以使用相同的键。
function Blog(props) {
  const sidebar = (
    <ul>
      {props.posts.map((post) =>
        <li key={post.id}>
          {post.title}
        </li>
      )}
    </ul>
  );
  const content = props.posts.map((post) =>
    <div key={post.id}>
      <h3>{post.title}</h3>
      <p>{post.content}</p>
    </div>
  );
  return (
    <div>
      {sidebar}
      <hr />
      {content}
    </div>
  );
}
 
const posts = [
  {id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
  {id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
  <Blog posts={posts} />,
  document.getElementById('example')
);
  • key 会作为给 React 的提示,但不会传递给你的组件。如果您的组件中需要使用和 key 相同的值,请将其作为属性传递:
const content = posts.map((post) =>
  <Post
    key={post.id}
    id={post.id}
    title={post.title} />
);

在 jsx 中嵌入 map()

  • JSX 允许在大括号中嵌入任何表达式,比如像这样:
function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
 
      )}
    </ul>
  );
}

React 组件 API

设置状态:setState

setState(object nextState[, function callback])
  • 参数说明
    • nextState,将要设置的新状态,该状态会和当前的state合并
    • callback,可选参数,回调函数。该函数会在setState设置成功,且组件重新渲染后调用。

合并nextState和当前state,并重新渲染组件。setStateReact事件处理函数中和请求回调函数中触发UI更新的主要方法。

  • 补充:
    • setState()并不会立即改变this.state,而是创建一个即将处理的statesetState()并不一定是同步的,为了提升性能React会批量执行state和DOM渲染。
    • setState()总是会触发一次组件重绘,除非在shouldComponentUpdate()中实现了一些条件渲染逻辑。

替换状态:replaceState

replaceState(object nextState[, function callback])
  • nextState,将要设置的新状态,该状态会替换当前的state。
  • callback,可选参数,回调函数。该函数会在replaceState设置成功,且组件重新渲染后调用。

replaceState()方法与setState()类似,但是方法只会保留nextState中状态,原state不在nextState中的状态都会被删除。

设置属性:setProps

setProps(object nextProps[, function callback])

替换属性:replaceProps

replaceProps(object nextProps[, function callback])

强制更新:forceUpdate

forceUpdate([function callback])

获取DOM节点:findDOMNode

DOMElement findDOMNode()

判断组件挂载状态:isMounted

bool isMounted()
  • 返回值:true或false,表示组件是否已挂载到DOM中

React 组件生命周期

组件的生命周期可分成三个状态:

  • Mounting:已插入真实 DOM
  • Updating:正在被重新渲染
  • Unmounting:已移出真实 DOM

生命周期的方法有:

  • componentWillMount 在渲染前调用,在客户端也在服务端。

  • componentDidMount : 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。

  • componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。

  • shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
    可以在你确认不需要更新组件时使用。

  • componentWillUpdate 在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。

  • componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。

  • componentWillUnmount 在组件从 DOM 中移除之前立刻被调用。

React AJAX

componentDidMount() {
    this.serverRequest = $.get(this.props.source, function (result) {
      var lastGist = result[0];
      this.setState({
        username: lastGist.owner.login,
        lastGistUrl: lastGist.html_url
      });
    }.bind(this));
  }

React 表单与事件

  • 使用 onChange 事件来监听 input 的变化,并修改 state。
class HelloMessage extends React.Component {
  constructor(props) {
      super(props);
      this.state = {value: 'Hello Runoob!'};
      this.handleChange = this.handleChange.bind(this);
  }
 
  handleChange(event) {
    this.setState({value: event.target.value});
  }
  render() {
    var value = this.state.value;
    return <div>
            <input type="text" value={value} onChange={this.handleChange} /> 
            <h4>{value}</h4>
           </div>;
  }
}
ReactDOM.render(
  <HelloMessage />,
  document.getElementById('example')
);

React Refs

React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。

这个特殊的属性允许你引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例。

class MyComponent extends React.Component {
  handleClick() {
    // 使用原生的 DOM API 获取焦点
    this.refs.myInput.focus();
  }
  render() {
    //  当组件插入到 DOM 后,ref 属性添加一个组件的引用于到 this.refs
    return (
      <div>
        <input type="text" ref="myInput" />
        <input
          type="button"
          value="点我输入框获取焦点"
          onClick={this.handleClick.bind(this)}
        />
      </div>
    );
  }
}
 
ReactDOM.render(
  <MyComponent />,
  document.getElementById('example')
);

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值