React 官方文档学习
渲染DOM元素和更新DOM元素
- ReactDOM.render(element1,element2)
解释:该函数用于将element1 渲染到 element2中,而element2 也就是React一般说的根节点。React会将element2中的内容替换成element1的内容。 如果不断调用该函数来生产新的UI元素,React就会比较新旧元素的区别而实际只更改这两个元素的不同点。
组件、Props\state
编写React组件可以通过两种方式来进行封装,一种是通过JavaScript函数来进行封装,一种是通过ES6的Class来定义组件。 官方的例子如下
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
上面的例子只是一个简单的React组件的示例,其中JS函数和ESClass格式下的组件返回的是一个React元素,而函数中的props则是用来接收外来的参数的。 React会将JSX所接收的属性(attributes)和子组件(children)转化为单个对象,并称为 props 。 ESClass组件每一次更新都会调用自身的render() 方法。
{
attributes1:value1,
attributes2:value2
}
Props 的只读性 组件无论是函数声明还是Class声明,都不可以修改自身的props。如果想要通过修改props来实现动态想过则需要借助State,State可以帮助我们完成这一操作。 State 如何使用State(还是用上面的例子进行讲解)
class Welcome extends React.Component {
constructor(props){
super(props);
this.state={date:new Date()};
}
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
完成以上的操作,就可以通过this.state 来操作props 里的值,而不需要直接操作props 了。但是这个操作并不是直接修改props 里的值,而是类似于对props 进行了一个复制,我们操作的是复制值。 关于this.state 需要注意的点: (1)除了构造函数中外的其他地方如下赋值是毫无意义的
this.state.xxxx = 'xxxxx';
this.setState({xxxx : 'xxxx'});
(2)state 的更新可能是异步的 一般来讲,React处于性能考虑,并不会一次次的加载setState 函数,而是可能把多个setState 函数合并成一个来调用,所以this.props 和this.state 可能会异步更新,从而导致错误,如下同时调用this.props 和 this.state 时。
this.setState({
counter: this.state.counter + this.props.increment,
});
要解决这个问题,我们就需要让setState 接收的是一个函数而不是对象。如下
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
(3)state 的更新会合并 当调用setState 时,React会把你提供的对象合并到当前的state 中,但是并不会修改其他的参数。
Class中的部分生命周期函数
要了解React的这部分生命周期函数,首先我们需要了解两个概念。 挂载(mount):到组件第一次被渲染到DOM中时,称之为挂载。 卸载(unmount):当组件被删除时,成为卸载。 这里要介绍的两个生命周期函数就是当组件被挂载或者卸载时调用的函数。 componentDidMount() 和 componentWillUnmount()
事件处理
React 中不能使用 false来阻止默认行为,而是通过preventDefault来实现,具体示例如下:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
为了在回调中可以调用this 来调用函数,我们必须在初始话函数中添加如下字段来保证初始化成功。
this.handleClick = this.handleClick.bind(this);
在render中返回 null 表示的意思是该组件不渲染。
状态提升
状态提升,按照我的理解就是:将组件中的部分方法指向父组件方法,但是值还是使用当前组件内的数据。 参考官方文档的示例:
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
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.handleCelsiusChange = this.handleCelsiusChange.bind(this);
this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
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={this.handleCelsiusChange} />
<TemperatureInput
scale="f"
temperature={fahrenheit}
onTemperatureChange={this.handleFahrenheitChange} />
<BoilingVerdict
celsius={parseFloat(celsius)} />
</div>
);
}
}
组合
对于一些组件,可能我们对于其内部的部分区域即将会展示什么部分没有明确的设计,而我们却希望我们将来可以直接添加这一部分的组件内容,所以组合的概念也就应运而生了。这个的概念和Vue.js中的插槽(solt)有些类似。 对于React,我们通过props.children 这个参数来将他们的子组件传递到渲染结果中。
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
}
如果其他组件想要在其中插入子组件的话可以进行如下的编码
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
}
但是prop.children 只是适用于只有一个添加点的情况,当拥有多个添加点的时候,我们就可以通过自定义的方式来达到我们的需求:
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}
over
|