React :元素构成组件,组件又构成应用。
React核心思想是组件化,其中 组件 通过属性(props) 和 状态(state)传递数据。
(1)命名:React 事件使用驼峰命名,而不是全部小写
(2)写法上:
HTML里:
React 中:
(3)阻止默认行为
在 React 中你不能通过返回 false(即 return false; ) 来阻止默认行为。必须明确调用 preventDefault 。
例如,阻止链接打开一个新页面的默认行为
HTML里:
Click me
而在 React 中, 应该这么写:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
Click me
);
}
ReactDOM.render(
,
document.getElementById('root')
);
或者这样写
function ActionLink() {
return (
{
e.preventDefault();
console.log('The link was clicked.');
}
}>
Click me
);
}
ReactDOM.render(
,
document.getElementById('root')
);
显然第一种写法更方便阅读。
这里需要注意的:我们是 给组件里的HTML元素 添加事件,而不是给组件本身添加事件
。
例如下面这种写法是错误
的
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
Click me
);
}
ReactDOM.render(
//不是给组件添加事件,是给组件元素添加
,
document.getElementById('root')
);
箭头函数解决this指向
缺点: 当事件响应逻辑比较复杂时,匿名函数的代码量会很大,会导致render函数变得臃肿,不容易直观地看出组件最终渲染出的元素结构。另外,每次render方法调用时,都会重新创建一个匿名函数对象,带来额外的性能开销,当组件的层级越低时,这种开销就越大,因为任何一个上层组件的变化都可能会触发这个组件的render方法。当然,在大多数情况下,这点性能损失是可以不必在意的。
例:
class MyComponent extends React.Component{
render(){
//ES6中默认this不与当前对象绑定,
//而箭头函数解决了this绑定这一问题,它可以将函数体内的this绑定到当前对象
return(
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
效果:(点击按钮后输出:hhhh)
箭头函数解决this指向
(1)在绑定组件方法时,用箭头函数
class MyComponent extends React.Component{
constructor(props){
super(props);
this.state = {number:0};
}
handleClick() {
this.setState({
number: ++this.state.number,
});
}
render(){
return(
{this.state.number}
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
(2)在定义组件方法时,用箭头函数
用到了ES7的特性,目前并非默认支持,需要Babel插件的支持,但是写法最为简洁,也不需要手动绑定this。但是这个特性还处于试验阶段。
缺点:
如果需要传参数(例如:《 三、处理事件响应 函数传参 方法一(2)》),这种方式会变得很鸡肋,多此一举:
class MyComponent extends React.Component{
constructor(props){
super(props);
this.state = {number:0};
}
handleClick = () => {
this.setState({
number: ++this.state.number,
});
}
render(){
return(
{this.state.number}
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
这样一来,再也不用手动绑定this了。但是这个特性还处于试验阶段,默认是不支持的。如果你是使用官方脚手架Create React App 创建的应用,那么这个特性是默认支持的。你也可以自行在项目中引入babel的transform-class-properties插件获取这个特性支持。
bind解决this指向
(1)在绑定组件方法时,用bind解决this指向
class MyComponent extends React.Component{
constructor(props){
super(props);
this.state = {number:0};
}
handleClick(){
this.setState({
number: ++this.state.number,
});
}
render(){
return(
{this.state.number}
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
(2)在constructor中,手动用bind解决this指向
例1:
class MyComponent extends React.Component{
constructor(props){
super(props);
this.state = {number:0};
//手动绑定this
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
this.setState({
number: ++this.state.number,
});
}
render(){
return(
{this.state.number}
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
效果:同上
例2:
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 这个绑定是必要的,使`this`在回调中起作用
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
效果:狠狠点击我
事件响应函数默认是会被传入一个事件对象Event作为参数的。如果想传入其他参数给响应函数呢?
但具体什么意思呢?看下面例子你就懂了
(1)
class MyComponent extends React.Component{
constructor(props){
super(props);
this.state = {
list:[1,2,3,4],
current:1
};
}
handleClick(item,event){
this.setState({
current: item,
});
console.log(item);
console.log(event);
}
render(){
return(
{this.state.list.map(
(item) => (
- this.handleClick(item,event)}>
{item}
)
)}
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
输出:(实际应用场景中,上面代码应该是像下面一样遍历数组,但第一个项样式会不一样)。点击不同的项后,会打印出该项的值
(2)
class MyComponent extends React.Component{
constructor(props){
super(props);
this.state = {
list:[1,2,3,4],
current:1
};
}
handleClick = (item,event) => {
this.setState({
current: item,
});
console.log(item);
console.log(event);
}
render(){
return(
{this.state.list.map(
(item) => (
- this.handleClick(item,event)}>
{item}
)
)}
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
效果:同上
把绑定this的操作延迟到render中,在绑定this的同时,绑定额外的参数:
class MyComponent extends React.Component{
constructor(props){
super(props);
this.state = {
list:[1,2,3,4],
current:1
};
}
handleClick(item){
this.setState({
current: item,
});
alert(item);
}
render(){
return(
{this.state.list.map(
(item) => (
-
{item}
)
)}
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
效果:同上
有没有感觉有鸡肋:虽然你不需要通过bind函数绑定this,但需要bind参数来绑定其他参数。
class MyComponent extends React.Component{
constructor(props){
super(props);
this.state = {
list:[1,2,3,4],
current:1
};
}
handleClick = (item) => {
this.setState({
current: item,
});
alert(item);
}
render(){
return(
{this.state.list.map(
(item) => (
-
{item}
)
)}
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
不管你在响应函数中有没有显式的声明事件参数Event,React都会把事件Event作为参数传递给响应函数,且参数Event的位置总是在其他自定义参数的后面。
例如,在《方法二、方法三 》中, handleClick的参数中虽然没有声明Event参数,但你依然可以通过 arguments[1]获取到事件Event对象。
class Son extends React.Component {
render() {
let index = 10;
return (
);
}
}
class Parent extends React.Component {
render() {
return ( );
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {value : 0};
}
handleClick(index,e) {
console.log(e);
this.setState({value: index});
}
render() {
console.log(this.state.value);
return ( this.handleClick(index,e)} />);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
点击button前输出:0,
点击button后输出:
前面都一样,要求在点击Son里的button时,将App的state.value值改为Parent中index值。
class Son extends React.Component {
render() {
return (
);
}
}
class Parent extends React.Component {
render() {
let index = 10;
return ( this.props.myHandleClick(index,e)} />);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {value : 0};
}
handleClick(index,e) {
console.log(e);
this.setState({value: index});
}
render() {
console.log(this.state.value);
return ( this.handleClick(index,e)} />);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
输出:同上