我们来写上次提到的组件,计数器。
组件
/src
下新建一个文件 Counter.js
import React, {Component} from 'react'
import './Counter.css'
class Counter extends Component{
render(){
return(
<div>
<div className="counter">
<input type="button" className="counterLeftButton" value="-" />
<input type="text" value="0" />
<input type="button" className="counterRightButton" value="+" />
</div>
)
}
}
export default Counter
- 这里没有用到元素渲染,就不用引入
ReactDOM
了。我们统一在index.js
中渲染。这里还引入了一个对应的 CSS 文件,稍微修饰一下。 - 注意
render
方法只能返回一个JSX元素,有多个并列元素时,外层用<div>
包一下就好。 - 最后一行用于导出类,这样在别的 js 文件中就可以引入了。如果不想写最后一行,可以在定义的时候直接这样写:
export default class Counter extends Component
嵌套
接下里,让这个 Counter
在页面中显示出来,两个办法:
- 在
public/index.html
中加入一个 HTML 元素,在src/index.js
中引入 Counter 并渲染到上面的 HTML元素中。
<div id="counter"></div>
...
import Counter from './Counter'
...
ReactDOM.render(<Counter />, document.getElementById('counter'));
...
- 直接把
<Counter />
嵌套到之前 hello 所在的JSX
元素中:
...
import Counter from './Counter'
...
render(){
return(
<div>
hello
<Counter />
</div>
)
}
emmm...就这样吧。
当然如果你愿意,多放几个也是没问题的。
...
render(){
const counters = []
for(var i = 0; i < 5; i++){
counters.push(<Counter/>)
}
return(
<div>
{counters}
</div>
)
}
...
事件
到现在为止,按钮点了没反应,也不能自己输入数字。是的,React.js
中无法直接更改 input
元素的值。不过使用 React.js
提供的监听事件机制,很容易就能做到,把 onChange
,onClick
等等, 像是 onXxx
这种事件当做属性,添加上对应的处理方法,设置到 JSX 元素上就可以了。
但是有一点,React.js
会直接调用这个方法,并没有通过对象调用,所以,如果要在方法中用 this
关键字,需要自己绑定 bind
。
<input type="text" value="0" onChange={this.handleInputValueChange.bind(this)}/>
Counter
类中加上 handleInputValueChange
方法
handleInputValueChange(event){
console.log(event.target.value)
}
然后,去修改 input 中
的值,你就能在控制台看到了……
摔,要直接在页面上让我看到啊混蛋,能不能给点力啊。
state
emmm...
看起来我们没办法直接在函数里访问 JSX 元素啊,不过,要是把 input
的 value
值设置为变量,在函数里修改再体现在页面上不就可以了。等同于,我们直接改了元素的 数据状态。React.js
为组件提供了 state 机制,我们在里面存放一个变量 count
就好。
constructor () {
super()
this.state = { count: 0 }
}
handleInputValueChange(event){
this.state.count = event.target.value
}
...
<input type="text" value={this.state.count} ... />
...
你会发现,还是不行…… emmm ...
自己直接修改 this.state
中的数据, React.js
不会给渲染的,这里需要调用 setState
:
this.setState({count: event.target.value});
同样的,给两个 button 加上 onClick
事件:
<input type="button" value="-" onClick={this.handleCountDecrease.bind(this)}/>
...
<input type="button" value="+" onClick={this.handleCountIncrease.bind(this)}/>
实现这两个方法,加上数据验证什么的,到现在为止,看起来似乎还不错。
props
但是,这个组件除了在购物车界面中使用,还有可能用在其他的地方,并且或许有另外的文本要求,这里使用了“-”,“+”,或许别的需求里需要其他字符,像是“<” 和 “>”,so,到此为止它的扩展性还是不够,如果可以在使用的时候直接在外部设置某些属性,就更好了。比如这样用:
<Counter leftButtonText="<" rightButtonText=">" />
我们在组件 Counter
中提前设置好默认值,通过 this.props.参数名
使用:
static defaultProps = {
leftButtonText: "-",
rightButtonText: "+"
}
...
<input type="button" value={this.props.leftButtonText} .../>
<input type="text" .../>
<input type="button" value={this.props.rightButtonText} .../>
...
ta-da
不过传进来的
props
不能在组件内部修改,需要改变的时候,可以通过父组件重新渲染。当然,如果需要,直接传函数进来也是可以的。在 index.js
中定义函数并传入:
handleCounterClick(event){
console.log("click handled by props")
}
render(){
return(
<Counter handleClick={this.handleCounterClick}/>
)
}
组件 Counter.js
中直接使用就好:
<div className="counter" onClick={this.props.handleClick}>...</div>
这下勉强算得上是一个组件吧。任何需要它出现的地方,直接使用 <Counter />
就OK了。
今天就到这里了。
网友评论