组件使你可以将 UI 划分为一个一个独立,可复用的小部件,并可以对每个部件进行单独的设计。
从定义上来说, 组件就像JavaScript的函数。封装内容, 达到重用的目的.
组件可以接收任意输入(称为”props”), 并返回 React 元素,用以描述屏幕显示内容
两种组件创建的方式
1.函数式组件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<!--react的核心库-->
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<!--react的与dom相关的一些功能-->
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!--将浏览器不支持的jsx语法转化为js语法-->
<script crossorigin src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
<!--
组件:组成的部件,可以接受任何props输入,并返回元素
-->
<script type="text/babel">
// 1. 创建一个基本的组件
function Welcome(){
return (
<div>
<p>哈哈</p>
</div>
)
}
// 2. 组件的使用
ReactDOM.render(
<Welcome></Welcome>,
document.getElementById('root')
);
</script>
类组件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<!--react的核心库-->
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<!--react的与dom相关的一些功能-->
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!--将浏览器不支持的jsx语法转化为js语法-->
<script crossorigin src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
<!--
组件:组成的部件,可以接受任何props输入,并返回元素
-->
<script type="text/babel">
// 1. 创建一个基本的组件
class Welcome extends React.Component{
render (){
return (
<div>
<p>哈哈</p>
</div>
)
}
}
// 2. 组件的使用
ReactDOM.render(
<Welcome></Welcome>,
document.getElementById('root')
);
</script>
生命周期
state和生命周期
state 允许 React 组件在不违反props规则的情况下, 根据用户操作, 网络响应, 或者其他随便什么东西, 来动态地改变其输出。
类似于vue中的data
state的定义
在类组件的constructor中定义state
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
}
****不能直接修改state(需要调用this.setState())
// 错误 这样将不会重新渲染一个组件:
this.state.comment = 'Hello';
// 正确 用 setState() 代替:
this.setState({comment: 'Hello'});
唯一可以分配 this.state 的地方是构造函数。
state(状态) 更新可能是异步的
使用回调函数的形式实现异步操作
需要将对象参数转变为回调函数的形式
// 错误
this.setState({
counter: this.state.counter + this.props.increment,
});
// 正确
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
使用另一种 setState() 的形式,它接受一个函数而不是一个对象。
这个函数将接收前一个状态作为第一个参数,应用更新时的 props 作为第二个参数:
state(状态)更新会被合并
你的状态可能包含几个独立的变量:
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
}
***调用this.setState()修改单个的状态不会影响其他的状态,只会合并当前修改的这一个状态
钩子函数是window消息处理机制的一部分,通过设置”钩子”,应用程序可以在系统级对所有消息,事件进行过滤,访问在正常情况下无法访问的消息
钩子函数的本质是一段用以处理系统消息的程序,通过系统调用,把它挂入系统
react组件的三个状态
1.mount
2.update
3.unmount
react针对以上三种状态都封装了hook函数
生命周期钩子详解
如下这些方法在组件实例被创建和被插入到dom中时被调用。
1.constructor()
---constructor初始化state的好地方。如果我们不需要初始化state,也不需要bind任何方法,那么在我们的组件中不需要实现constructor函constructor在组件被mounted之前调用,我们的组件继承自React.Component,constructor函数中我们在其他操作前应该先调用super(props),否则this.props将会是undefined。
---constructor初始化state的好地方。如果我们不需要初始化state,也不需要bind任何方法,那么在我们的组件中不需要实现constructor函数。
----注意下面这种情况,很容易产生bug,我们通常的做法是提升state到父组件,而不是使劲的同步state和props。
constructor(props) {
super(props);
this.state = {
color: props.initialColor
};
}
componentWillMount()
--此方法在mounting之前被立即调用,它在render()之前调用,因此在此方法中setState不会触发重新渲染。此方法是服务器渲染中调用的唯一的生命周期钩子,通常我们建议使用constructor()。
render()
--render()方法是react组件必须的,它检查this.props和this.state并且返回一个React元素,我们也可以返回null或false,代表我们不想有任何的渲染。
--render()方法应该是一个纯方法,即它不会修改组件的state,在每一次调用时返回同样的结果。它不直接和浏览器交互,如果我们想要交互,应该在componentDidMount()或者其他的生命周期函数里面。
componentDidMount()
--此方法在组件被mounted之后立即被调用,初始化dom节点应该在此方法中,如果需要从远端健在数据,这里是实例化网络请求的好地方,此方法中setState会触发组件重新渲染。
Updating
props和state的改变产生更新。在重新渲染组建时,如下的方法被调用
componentWillReceiveProps()
一个已经mounted的组件接收一个新的props之前componentWillReceiveProps()被调用,如果我们需要更新state来响应prop的更改,我们可以在此方法中比较this.props和nextProps并使用this.setState来更改state。
注意,即使props没有改变,React也可以调用这个方法,因此如果你只想处理改变,请确保比较当前值和下一个值。当父组件导致你的组件重新渲染时,可能会发生这种情况。
React在组件mounting期间不会调用此方法,只有在一些组件的props可能被更新的时候才会调用。调用this.setState通常不会触发componentWillReceiveProps。
shouldComponentUpdate()
使用此方法让React知道组件的输出是否不受当前state或props更改的影响。默认行为是在每次state更改时重新渲染组件,在大多数情况下,我们应该默认改行为。
当接收到新的props或state时,shouldComponentUpdate()在渲染之前被调用。默认返回true,对于初始渲染或使用forceUpdate()时,不调用此方法。返回false不会阻止子组件的state更改时,该子组件重新渲染。
如果shouldComponentUpdate()返回false,那么componentWillUpdate(),render()和componentDidUpdate()将不会被调用。在将来,React可能将shouldComponentUpdate()作为提示而不是strict指令,返回仍然可能导致组件重新渲染。
componentWillUpdate()
当接收新的props或state时,componentWillUpdate()在组件渲染之前被立即调用。使用此函数作为在更新发生之前执行准备的机会。初始渲染不会调用此方法。
注意:这里不能调用this.setState()(如果调用会怎么样?好奇心很重呀,试了一下,会产生死循环,一直更新。
如果我们需要更新state以响应props的更改,我们应该使用componentWillReceiveProps()
render()
render()方法是react组件必须的,它检查this.props和this.state并且返回一个React元素,我们也可以返回null或false,代表我们不想有任何的渲染。
render()方法应该是一个纯方法,即它不会修改组件的state,在每一次调用时返回同样的结果。它不直接和浏览器交互,如果我们想要交互,应该在componentDidMount()或者其他的生命周期函数里面。
componentDidUpdate()
此函数在更新后立即被调用。初始渲染不调用此方法。
当组件已经更新时,使用此操作作为DOM操作的机会。这也是一个好的地方做网络请求,只要你比较当前的props和以前的props(例如:如果props没有改变,可能不需要网络请求)。
Unmounting
当从dom中移除组件时,这个方法会被调用
componentWillUnmount()
此函数在组件被卸载和销毁之前被立即调用。在此方法中执行一些必要的清理。例如清除计时器,取消网络请求或者清理在componentDidMount中创建的任何DOM元素。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<!--react的核心库-->
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<!--react的与dom相关的一些功能-->
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!--将浏览器不支持的jsx语法转化为js语法-->
<script crossorigin src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
<script type="text/babel">
// 创建一个类组件
class LifeCycle extends React.Component {
// 1. mount阶段
constructor(props) {
super(props);
this.state = {name: 'wlt'};
this.changeState = this.changeState.bind(this);
console.log('constructor');
}
componentWillMount() {
console.log('componentWillMount');
}
render() {
console.log('render');
return (
<div className="life-cycle-bg">
<p>Hello {this.props.value}</p>
<p>Hello {this.state.name}</p>
<button onClick={this.changeState}>改变lifeCycle的state</button>
</div>
);
}
componentDidMount() {
console.log('componentDidMount');
}
// 2. update阶段
componentWillReceiveProps(nextProps) { // 只作用于属性的变化,不作用于状态的变化
console.log('componentWillReceiveProps');
}
shouldComponentUpdate(nextProps, nextState) {
console.log('shouldComponentUpdate');
return true;
}
componentWillUpdate(nextProps, nextState) {
console.log('componentWillUpdate');
}
// ---- render会重新执行
componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate');
}
// 3. Unmount阶段
componentWillUnmount(prevProps, prevState) {
console.log('componentWillUnmount');
}
// 修改状态
changeState() {
this.setState({name: 'sxm'});
}
}
class ParentLifeCycle extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 'World',
destroyed: false,
rerender: false
};
this.handleChange = this.handleChange.bind(this);
this.destroyComponent = this.destroyComponent.bind(this);
this.handleRerender = this.handleRerender.bind(this);
}
handleChange() {
this.setState((prevState, props) => ({
value: prevState.value + ' wlt'
}));
}
handleRerender() {
this.setState({rerender: true});
}
destroyComponent() {
this.setState({destroyed: true});
}
render() {
if(this.state.destroyed) return null;
return (
<div className="parent-life-cycle-bg">
<p>
<button onClick={this.handleChange}>改变LifeCyle的props</button>
<button onClick={this.handleRerender}>父组件重新渲染,子组件re-render</button>
<button onClick={this.destroyComponent}>删除组件</button>
</p>
<LifeCycle value={this.state.value}/>
</div>
);
}
}
ReactDOM.render(
<ParentLifeCycle />, document.getElementById('root')
);
</script>
state 和 生命周期
实现一个基本的定时器功能
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<!--react的核心库-->
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<!--react的与dom相关的一些功能-->
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!--将浏览器不支持的jsx语法转化为js语法-->
<script crossorigin src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
<script type="text/babel">
// 创建一个组件 -- 使用函数式组件
function Clock(){
// 创建元素
const element = (
<div>
<h1>hello world!</h1>
<h2>It is {new Date().toLocaleTimeString()}</h2>
</div>
)
// 使用render函数渲染已经创建的元素
ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(Clock,1000)
</script>
存在的问题
完成定时器的功能,使用组件化的形式进行封装的时候,在进行组件调用的时候应该能够直接通过 就能完成一个定时器,而不用再配合外部的js操作
这样做的话能够实现相关的功能,但是不利于复用
网友评论