一、参考的网址:
由于英文水平有限,主要参考第一个网址的教程进行入门。
二、前期准备
在本机上安装并配置node.js,熟悉node.js得到基本使用模式。
可以 参考:node.js安装配置
当然,JAVA方向的日常开发通常不会用到node.js,没兴趣的话,可以跳过这一步。
如果使用菜鸟教程进行React的入门学习,建议先熟悉ES6 的语法,这样可以更方便的理解提供的案例。
二、React的安装
要使用React,只需要在页面中引入:
react.min.js 、react-dom.min.js 和 babel.min.js三个类库即可。
可以在官网 https://reactjs.org/ 下载最新版,并直接引入到项目中。
其中,react.min.js是React的核心类库,react-dom.min.js用于与DOM的交互,babel.min.js用于将ES6转为ES6、并内嵌了对JSX的支持。
需要注意的是:如果我们需要使用 JSX,则 <script> 标签的 type 属性需要设置为 text/babel。
三、React元素渲染
元素是React的最小单元,用于描述显示在页面上的内容。
通常,我们会在页面上定义一个指定id的根节点,然后使用ReactDOM.render()方法,将元素渲染到页面中。
如:
设置根节点如下:
<div id = "example" ></div>
定义一个元素element,并将其渲染到这个根节点中:
var element = <p>这里是希望渲染到元素中的内容</p>;
ReactDOM.render(
element,
document.getElementById("example")
);
注意,元素一旦渲染到根节点当中去,目前无法动态的变更改元素中的内容,如果需要改变页面徐然的效果,只能定义一个新的元素,并重新调用一次ReactDOM.render方法,将这个新的元素重新渲染到同一根节点当中去。
此外,值得注意的是 React DOM 首先会比较元素内容先后的不同,而在渲染过程中只会更新改变了的部分。
四、React JXS
React中,可以使用JXS代替js,这是一种形式上类似于HTML的语法,并且,类似于JavaScript,他可以写在一个单独的js文件中,供页面进行引用。当然,在React中,并不强制要求使用JXS。
上文用到的ReactDOM.render(),就是一个JXS表达式。
1、使用js表达式
在JXS中,仍然可以使用js表达式,将需要用到的js表达式写在花括号{}中即可。
如:
ReactDOM.render(
<h1>括号中是一个js表达式{1+1}</h1>,
document.getElementById("example")
);
注意,定义的元素和document.getElementById()渲染语句之间,一定要以逗号隔开。否则语句将不生效。
另外,JXS中,不支持if else的表达式,而应当用三目运算符(?:)代替
如:
ReactDOM.render(
<h1>{1==2?'yes':'no'}</h1>,
document.getElementById('example')
);
2、使用内联样式
在JSX中,可以设置元素的样式。通常,使用内联样式来实现。
如:
var myStyle = {
color: 'red',
fontSize : 20
};
ReactDOM.render(
<h1 style = {myStyle}>使用花括号引入样式</h1>,
document.getElementById('example')
);
上述例子中,JXS会自动为fontSize补上单位px.
个人再使用RenderDOM.render()的时候,有一个坏习惯,喜欢在document.getElementById('example')这个语句后头补一个分号,或者把RenderDOM.render()中的内容用花括号框起来,写成RenderDOM.render({}),这样会导致语句不生效!
3、注释
JXS的注释,写在{/**/}中。
如:
ReactDOM.render(
<div>
<h1>使用花括号插入注释</h1>
{/*这里是一段注释*/}
</div>,
document.getElementById('example')
);
在JXS中引入的语句必须是一个完整的整体。也就是说,如果需要插入注释的话,需要将注释和其他语句用<div>等容器包裹起来。
4、数组
JXS允许插入数组,并且会自动展开所有的数组元素。当然,说是数组,这里更像是将多个元素包裹在一个容器中,组成一个新的大元素的方式。在JXS中,用花括号来引用数组,且数组一定要用<div>等容器包裹起来。
如:
var arr = [
<h1>数组元素1</h1>,
<h2>数组元素2</h2>,
];
ReactDOM.render(
<div>{arr}</div>,
document.getElementById('example')
);
5、JXS渲染HTML组件
与HTML想对应,React中使用className属性来替代HTML中的class,用htmlFor来替代for
简单来说,就是React 的 JSX 使用大、小写的约定来区分本地组件的类和 HTML 标签。原生 HTML 元素名以小写字母开头,而自定义的 React 类名以大写字母开头。
五、React组件
可以使用函数或ES6 class语法来定义React组件,一个React组件类似于一个HTML标签,可以直接用于组成元素。
如:
/**使用function来定义一个组件
* 注意:组件名称首字母必须大写!
* 注意,prop写法固定,指传入组件的属性
**/
function ReactEle(prop) {
return <h1>这里是组件中的内容,传入的属性:{prop.name}</h1>;
}
//引用组件
ReactDOM.render(
<ReactEle name = 'name'/>,
document.getElementById('example')
);
这里注意一下组件定义中的{prop.name}语法,这里是将引用组件时,传入的name属性的值取出来。
另外,还可以通过多个组件组合的形式定义一个新的组件。但是需要注意,组件类只能包含一个顶层标签,否则会报错。
六、React 状态(state)
从这一部分开始,学习怎样使用React实现简单的功能。
React的状态(state)是组件渲染的数据依据。除了拥有它的组件之外,其他组件不可访问。React 里,只需更新组件的 state,就可以根据新的 state 重新渲染用户界面(不要操作 DOM)。
由于菜鸟教程的状态部分安利基本使用ES6表达式来写,感觉比较抽象,这部分的内容主要参考:
1、什么是state
并不是所有的React变量都可以称作是state。要能够成为一个state,至少需要满足以下几个条件:
- 该变量无法通过prop从父组件中获取;
- 该变量在组件的生命周期中发生了变化;
- 该变量无法通过其他的prop属性值或是state值计算得到;
- 该变量在render中有被使用到。
2、state和prop的区别
state是可变的,而prop对于使用它的组件而言,是只读的,要想改变prop的值,只能通过修改父组件传入的值来实现。
3、state的修改与使用
直接修改state,并不会修改组件中的值,而应当使用setState()方法;
如:
将state中的title属性的值改为‘React’:
this.setState({title: 'React'});
需要注意的是,React中,获取state是异步的,有时,React还会自动将多次state的更新合并到一次来进行,所以,不能依赖this.state来进行计算,这样,你用于计算的数值可能是已过期的数据。
此外,state允许部分更新。当一个state中包含有多个属性值,但是本次更新只需要修改其中一个值时,可以直接调用setState方法,仅对其中的指定属性进行修改。
4、不同类型的state修改方式
React官方建议,将State当做一个不可变的对象。这一点可以理解为,每一次修改State中包含的状态的值的时候,实际上,是重新创建了一个状态对象。类似于JAVA中的String,修改String类型的值的时候,实际上是将指针指向了一个新的对象。
不同类型的状态,当状态的值发生变化时,创建新状态的方式都有所不同。主要可以区分为以下三类:
(1)状态的类型为不可变的类型,如:Boolean、字符串、数字、null、underfined等。直接为它赋一个新的值即可:
this.setState({
count: 1,
title: 'React',
success: true
})
(2)状态的类型为数组。注意:此时应当使用concat(拼接)、filter(过滤)、slice(截取)等会返回一个新数组的方式,对数组类型的对象进行赋值,而非使用push、pop、shift、unshift、splice这类只在元数组基础上进行变更的方法。
如:假设存在一个数组类型的状态book,此时要对这个状态进行修改:
var books = this.state.books;
// 使用concat创建新数组,为元数组增加一个对象
this.setState({
books: books.concat(['React Guide']);
})
//从books中截取部分内容作为新的对象
this.setState({
books: books.slice(1,3);
})
//从books中过滤部分元素后,作为新状态
this.setState({
books: books.filter(item => {
return item != 'React';
});
})
(3)状态的类型是普通对象(不包含字符串、数组)
此时,可以使用ES6 的Object.assgin方法,或使用对象扩展语法(object spread properties)
总结一下,创建新的状态对象的关键是,避免使用会直接修改原对象的方法,而是使用可以返回一个新对象的方法。当然,也可以使用一些Immutable的JS库,如Immutable.js,实现类似的效果。
七、props
state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。
1、props设置属性的默认值
可以通过组件类的 defaultProps 属性为 props 设置默认值,如:
function PropsExap(props) {
return <h1>读取props中name元素的值:{props.name}</h1>;
}
PropsExap.defaultProps = {
name: '默认名称'
};
const element = <PropsExap/>;
ReactDOM.render(
element,
document.getElementById('example')
);
2、props验证器
props可以实现类似于Bootstrap Validator 的传入数据验证。
首先,引入propTypes验证插件:
<script src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>
然后就可以调用其中的验证器来对传入数据进行验证。详参相关文档。
八、React事件处理
React时间处理与DOM基本一致,只是写法上略有不同,主要体现在一下几点:
1、React 事件绑定属性的命名采用驼峰式写法,而不是小写。
2、如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM 元素的写法)
如,处理按钮的点击事件:
//HTML写法
<button onclick = "doSomthisn()"/>
//React写法
<button onClick = {doSomthisn}/>
3、React中不能使用返回false来组织默认行为,而必须使用preventDefault.
使用 React 的时候通常你不需要使用 addEventListener 为一个已创建的 DOM 元素添加监听器。你仅仅需要在这个元素初始渲染的时候提供一个监听器。
4、React中,累的方法不会主动绑定this,通常情况下,如果你没有在方法后面添加 () ,例如 onClick={this.handleClick},你应该为这个方法绑定 this。如,使用bind()方法:
this.handleClick = this.handleClick.bind(this);
值得注意的是,通过 bind 方式向监听函数传参,在类组件中定义的监听函数,事件对象 e 要排在所传递参数的后面
//事件中绑定参数的顺序和函数中的不相同
<button onClick={this.handleClick.bind(this, props0, props1, ...}></button>
handleClick(porps0, props1, ..., event) {
// your code here
}
九、React条件渲染
React 中的条件渲染和 JavaScript 中的一致,使用 JavaScript 操作符 if 或条件运算符来创建表示当前状态的元素,然后让 React 根据它们来更新 UI。
如:
function Login(props) {
return <h1>请先登录!</h1>;
}
function Welcome(props) {
return <h1>欢迎使用!</h1>
}
function Greeting(props) {
const isLoginedIn = props.isLoginedIn;
if(isLoginedIn ) {
return <Welcome/>;
} else {
return <Login/>;
}
}
ReactDOM.render(
//这里传入的值必须要用花括号包起来!
<Greeting isLoginedIn = {true}/>,
document.getElementById("example")
);
可以使用花括号包裹的方式,在JXS中嵌入任何表达式,包括js的逻辑与&&、三目运算符等。
在 JavaScript 中,true && expression 总是返回 expression,而 false && expression 总是返回 false。
因此,如果条件是 true,&& 右侧的元素就会被渲染,如果是 false,React 会忽略并跳过它。
此外,让render函数返回null,可以阻止组件被渲染。且组件的 render 方法返回 null 并不会影响该组件生命周期方法的回调。
十、React列表&keys
在组件中接收数组参数时,每一个列表元素都必须赋一个key值,否则会报错。
如:用map()遍历数组生成列表, key = {number.toString} 语句是必须的
function ChangeToItemList(props) {
const numbers = 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(
<ChangeToItemList numbers={numbers} />,
document.getElementById('example')
);
一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据的 id 作为元素的 key,当元素没有确定的 id 时,你可以使用他的序列号索引 index 作为 key
const todoItems = todos.map((todo, index) =>
// 只有在没有确定的 id 时使用
<li key={index}>
{todo.text}
</li>
);
此外,数组元素中使用的 key 在其同级的组件之间之间应该是独一无二的。然而,它们不需要是全局唯一的。在生成两个不同的数组时,可以使用相同的键。
一个在JXS中嵌入map的例子:
var ListItem = (props) => { //es6中箭头函数
return <li>{props.value}</li>;
}
function NumberList(props) {
var numbers; //声明在外面是因为 {} 中不能出现var,const,let等这种关键字
return (
<ul>
{
numbers = props.numbers, //注意这里要加逗号
numbers.map((number) =>
<ListItem key={number}
value={number} />
)}
</ul>
);
}
var arr = [1,2,3]; //要传递的参数
ReactDOM.render(
<NumberList numbers={arr}/>, //这里的numbers就是props下的numbers,即props.numbers
document.all('example')
);
十一、React组件API
- 设置状态:setState
- 替换状态:replaceState
- 设置属性:setProps
- 替换属性:replaceProps
- 强制更新:forceUpdate
- 获取DOM节点:findDOMNode
- 判断组件挂载状态:isMounted
详情可参考:
十二、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
React 组件的数据可以通过 在componentDidMount 中调用 Ajax (调用方法同js)来获取,当从服务端获取数据时可以将数据存储在 state 中,再用 this.setState 方法重新渲染 UI。
当使用异步加载数据时,在组件卸载前使用 componentWillUnmount 来取消未完成的请求(如:this.serverRequest.abort();)。
十四、React表单与事件