11、React系列之--state状态
PS:转载请注明出处 React 教程系列
注:本篇文章采用ES6的写法,以后不没有特别说明都使用ES6+yarn+webpack去写demo 1、什么是state我们都说React是一个状态机,体现是什么地方呢,就是体现在state上,通过与用户的交互,实现不同的状态,然后去渲染UI,这样就让用户的数据和界面保持一致了。state是组件的私有属性。 在React中,更新组件的state,结果就会重新渲染用户界面(不需要操作DOM),一句话就是说,用户的界面会随着状态的改变而改变。 PS: state 只能在本组件中去初始化,并且 state 只能被本组件去修改和仿问,不能被外部仿问和修改,所以也可以说,state 是组件私有的。 2、state的使用方法
对于state的使用方法,在ES5中和Es6中使用是不一样的,我们以ES6为例,在组件的构方法中如下设置即可,设置一个默认的state属性。 constructor(props) { super(props); this.state={ key:value,... } }
更新state调用以下方法 this.setState({ key:value }) ;
千万不要这么干,this.state.key = XXX ; 这样不会重新渲染界面
PS:如果调用了setState()方法以后,就会调用render()方法,也就是前面说的,用户的界面会随着状态的改变而改变。
这一步是在2步的基础上的,setState()会触发diff算法最终确定是否要更新。 3、什么样的组件应该有state应该说大部分的组件根据props来取得数据并渲染,但是用户输入,请求服务器,操作数据库等情况下就需要state了.官方的建议是尽量构建无状态的组件,是为了提高性能,减少渲染次数,做法就是构建几个无状态的组件,在这之上构建一个有状态和用户和服务交互 ,然后通过props来传递给无状态的组件。
反例 请不要这样做
this.state.comment = 'Hello';
正确的做法是使用setState()方法 正确的做法
this.setState({ comment:'Hello',})
用官方的话说就是this.props和this.state更新的时候可能是异步的,所以你不应该依靠他们的值来计算下一个状态 以下是错误的例子 反例
this.setState({
counter: this.state.counter + this.props.increment,});
正确的例子 正确的例子
this.setState((prevState,props) => ({ counter: prevState.counter + props.increment }))
当你调用 setState() ,React会合并你提供的对象到当前的 state 里 比如:你的state可能包含几个独立的变量 constructor(props) { super(props); this.state = { posts: [],comments: [] };
}
然后你可以通过调用setState()来独立的更新他们 componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
这个合并是浅合并,所以 this.setState({comments}) 会让 this.state.posts 完整,但是会完全替换掉 this.state.comments . 4、开始撸码说一千,道一万,都是在理论级别,下面我们从0开始写一个简单的Demo来体验一下state。下面使用webpack+yarn来写一个demo。 在mac环境下,win下基本差不太多
mkdir state
cd state
yarn init
在上面步骤一路回车即可
yarn add react react-dom webpack webpack-dev-server babel-core babel-loader babel-preset-react bable-preset-es2015 babel-preset-stage-0 --dev
然后回车,等待安装依赖,如果没有什么问题就可以在package.json中看到如下结果(红色框中) 以上就表明你的依赖安装成功了
{
"presets":["react","es2015","stage-0"] }
<!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">
<title>Hello state</title>
</head>
<body>
<div id="container"></div>
<script src="bundle.js"></script>
</body>
</html>
# main.js
import React from 'react' ;
import ReactDOM from 'react-dom' ;
import State from './State.js' ;
ReactDOM.render(
<State />,document.getElementById('container')
) ;
# State.js
import React,{ Component,PropTypes } from 'react';
/** * 使用es6语法 定义一个State组件 */
export default class State extends Component {
constructor(props) {
super(props);
this.state = { //初始化state
countnum:0,};
}
/** * 点击事件方法 countnum+1 */
_handlerEvent(){
this.setState({
countnum:this.state.countnum+1,})
}
render() {
return (<div>
{this._renderView()}
</div>);
}
/** * 渲染一个button组件 */
_renderView(){
return(
<div>
<button onClick={this._handlerEvent.bind(this)}>点击{this.state.countnum}次</button>
</div>
);
}
}
module.exports = {
entry:__dirname+'/app/main.js',output:{
path:__dirname+'/public',filename:'bundle.js'
},devServer:{
contentBase: "./public",//本地服务器所加载的页面所在的目录
historyApiFallback: true,//不跳转
inline: true//实时刷新
},module:{
loaders:[
//babel配置
{
test:/.js$/,exclude: /node_modules/,loader: 'babel-loader'
}
]
}
}
图中的蓝色部分就是我们添加的脚本,即: "scripts":{
"start":"webpack-dev-server --progress --port 8888"
}
以上我们就完成了一个简单的state的例子,从这个例子中我们可以看到每当我点击按钮的时候组件的状态都会发生改变,计数就加1了,但是当我们调用了setState()方法到底有没有刷新界面呢?我们再测试一下
从图中可知我们只是在原有的基础上添加了现代战争方法,用来测试render方法调用次数,然后保存,看结果(打开chrome的调试栏) 从图中我们可以清楚的看到,我们点击了多少次,render方法就调用了多少次,所以说当调用了setState()方法就会重新渲染界面 到此为止,我们对state就有一个大体的认知了。下面我们来说一个无状态组件的例子。 5、无状态的组件1、什么是无状态组件无状态组件顾名思义就是没有状态的组件我们上面提到过无状态的组件,官方建议的是尽量让组件无状态化,但是肯定有一个地方要状态化的,一般做法是把要组合的组件无状态化,宿主组件有一个状态设置(一般情况下,也就是父组件更新子组件的时候,但是有时会反过来) 接下来我们构建一个无状态的组件,然后通过和用户交互(点击)的时候把状态通过props传给无状态的组件达到更新UI的目的,这么说可能有点绕我们看下面图来直观的理解一下 上图就是这一过程的一个伪代码,很好理解。 2、我们通过一个demo来直观感受一下
# PassStateOfprops.js 此组件可以当作有状态的父组件
import React,PropTypes } from 'react';
import StateLess from './StateLess.js' ;
/** * 通过 props来传递state 达到更新组件的目的 */
export default class PassStateOfprops extends Component {
constructor(props) {
super(props);
this.state = { //初始化state
list:[
'111','222','333'
]
}
}
/** * 渲染界面 */
render() {
return (<div>
{this._renderButton()}
{/* 将state通过props传递到无状态组件StateLess中 */}
<StateLess datas={this.state.list}/>
</div>);
}
/** * 渲染一个button */
_renderButton(){
return(
<div>
<button onClick={this._handlerEvent.bind(this)}>改变值</button>
</div>
) ;
}
/** * 点击事件 */
_handlerEvent(){
this.setState({
list:['444','555','666']
}) ;
}
}
# StateLess.js 定义一个无状态的组件
import React,PropTypes } from 'react';
/** * 定义一个无状态的组件 */
export default class StateLess extends Component {
render() {
return (<div>
<ul>
{
this.props.datas.map(function (data) {
return (
<li>{data}</li>
)
})
}
</ul>
</div>);
}
}
其中黄色部分就是我们修改的部分.
我们看到通过props传递state到无状态的组件成功运行了,所以我们以后在项目中开发,尽量使用无状态化的组件,把这种思想和习惯从现在就养成。 本demo的地址https://github.com/githubchen001/react-lesson/tree/master/lesson02/09-state (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |