函数组件/类定义组件
使用普通的JavaScript函数即可定义一个React组件:
function MyComponent(props) {
return <h1>Props value: {props.value}</h1>;
}
函数接受一个单一的props对象,返回值是React元素,这种方式就是函数定义组件,即组件是一个函数。使用ES6的Class也可以定义一个组件:
class MyComponent extends React.Component {
render() {
return <h1>Props value: {this.props.value}</h1>;
}
}
组件的props与state
pros是一个组件的属性,是只读的,不可以对组件的属性进行写操作。state是一个组件的状态对象,包含了组件在不同生命周期的各种状态数据。注意以下几点:
- 状态不可以直接更新,需要使用setState函数来更新
- 状态只能在构造函数中初始化
- 调用setState更新状态时,提供的对象会被合并到当前组件状态中
- 独立更新
- 浅合并
父组件通过设置子组件的props来向下传递数据,即数据是从上到下单向流动的。
事件处理
几个注意点:
- return false不会阻止默认行为,需要使用以下方式:
function ActionLink(props) {
function handleClick(e) {
e.preventDefault();
console.log('Link has been clicked');
}
return (
<a href='#' onClick={handleClick}>
Click me.
</a>
)
}
- ES6的语法不会将类的方法默认绑定到this上,因此在绑定事件处理函数时需要在构造器中显式声明:
class Toggle extends Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
)
}
}
如果不想使用bind,则有两种语法可以支持:
//babel提供的属性初始化语法,适用于不传参数的监听函数
class Toggle extends Component {
handleClick = (e) => {
//...
}
}
//绑定事件回调中的箭头函数
class Toggle extends Component {
render() {
return (
<button onClick={ e => this.handleClick(e) }>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
)
}
}
- 向事件函数传递其他参数并且使用到事件对象时,事件对象必须指定,并且要排在事件监听函数参数的最后:
class Popper extends Component {
construtor(props) {
super(props);
this.state = {name: 'Michael Yan'}
}
popName(name, e) {
e.preventDefault();
console.log(name);
}
render() {
// onClick也可以显式绑定:this.popName.bind(this, this.state.name)
return(
<div>
<p>Welcome:</p>
<a href='https://reactjs.org' onClick={e => this.popName(this.state.name, e)}
</div>
)
}
}
- 不使用事件对象时,两种方式都可以,例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
<title>Document</title>
</head>
<body>
<div id='root'></div>
<script type="text/babel">
function toCelsius(fahrenheit) {
return (fahrenheit - 32) * 5 / 9;
}
function toFahrenheit(celsius) {
return (celsius * 9 / 5) + 32;
}
function tryConvert(temperature, convert) {
const input = parseFloat(temperature);
if (Number.isNaN(input)) {
return '';
}
const output = convert(input);
const rounded = Math.round(output * 1000) / 1000;
return rounded.toString();
}
function BoilingVerdict(props) {
if(props.celsius >= 100){
return <p>The water would boil.</p>;
}
return <p>The water would not boil.</p>;
}
const scaleNames = {
c: 'Celsius',
f: 'Fahrenheit'
}
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
}
handleChange = e => {
this.props.onTemperatureChange(e.target.value)
}
render() {
const temperature = this.props.temperature;
const scale = this.props.scale;
return (
<fieldset>
<legend>Enter temperature in {scaleNames[scale]}:</legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
)
}
}
class Calculator extends React.Component {
constructor(props) {
super(props);
this.state = {temperature: '', scale: 'c'}
}
handleCelsiusChange(temperature) {
this.setState({
scale: 'c', temperature
})
}
handleFahrenheitChange(temperature) {
this.setState({
scale: 'f', temperature
})
}
render() {
const scale = this.state.scale
const temperature = this.state.temperature
const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
return (
<div>
<TemperatureInput
scale="c"
temperature={celsius}
onTemperatureChange={celsius => this.handleCelsiusChange(celsius)}
/>
<TemperatureInput
scale="f"
temperature={fahrenheit}
onTemperatureChange={fahrenheit => this.handleFahrenheitChange(fahrenheit)}
/>
<BoilingVerdict celsius={parseFloat(celsius)} />
</div>
)
}
}
ReactDOM.render(
<Calculator />,
document.getElementById('root')
)
</script>
</body>
</html>