依照官方文档和例程博客,实现了1个简单的输入框组件。
如果想了解官方案例,请参考深入理解 React
总结1下,1个简单的React.js利用应依照以下步骤构建:
个人认为这里的难点在于如何拆分用户界面,粒度过大不利于组件化的重用,粒度太小的话,显得冗余过量,并且复杂度陡升。本人最开始尝试细化的拆分,尽可能让1个组件只完成1个很小的功能需求,但最后反而不知道如何给每一个组件分配其任务。
另外一个难点来源于对state的判断,其实如果能够辨认出最小的state,读者会发现1个复杂的组件所需的state数量其实很少。
在React.js中,有两种数据模型,state代表的是会动态变化的状态,props代表的是父级传递而来的属性,state会反过来更新UI,而props只是1次性设置填充。
我们的组件要完成以下功能:
原型比较简单,样式以下:
JSON接口数据以下:
{
labelText: "酒店地址",
hinderText: "请填写酒店地址",
buttonImgSrc:
regExp: /^\w{5,8}$/
}
我们通过JSON数据设置输入框组件的label标签、Input的placeholder属性和对用户输入的正则验证。
在完成用户界面切分的进程中,最开始,如图原型图所示,做了非常细粒度的拆分,拆分结构以下:
这里,将LimitedInputBox
作为最外面的容器,包裹全部组件,子组件分为3部份,Title
即是1个label
标签,用来显示该输入框组件的名称(或说标题),InputBox
即是1个input
标签,用来接收用户输入,ClearButton
可以用1个img
标签,用来清除input
输入框内容。刚开始准备用另外1个容器包裹InputBox
和ClearButton
,发现这样过于冗余因而二者还是和Title
作为同1级组件比较好。
后来思来,觉得过于拆分了,最小单位与HTML原生标签同1级别,没成心义,因此,最后只保存了1个组件,就称之为LimitedInputBox
。即:
首先,不需要斟酌用户交互,直接将数据模型渲染到UI上。行将数据渲染和用户交互两个进程拆分开来。
这样做比较简单,由于构建静态版本的页面只需要大量的输入,而不需要思考;但是添加交互功能却需要大量的思考和少许的输入。
为了创建1个渲染数据模型的利用的静态版本,你将会构造1些组件,这些组件重用其它组件,并且通过 props 传递数据。 props 是1种从父级向子级传递数据的方式。
本例中,的props
就是第1步构建的JSON数据。
斟酌到第2步中我采取了两种拆分方式,这里给出相应的代码:
/** author : River He**/
//细分结构
var data = {
labelText: "酒店地址",
hinderText: "请填写酒店地址",
buttonImgSrc: "eliminate.png",
regExp: /^\w{5,8}$/
};
var Title = React.creatClass({
render: function() {
return (
<label>{this.props.labelText}</label>
);
}
});
var InputBox = React.createClass({
render: function() {
return (
<input
placeholder={this.props.hinderText}
regExp={this.props.regExp}>
</input>
);
}
});
var ClearButton = React.createClass({
render: function() {
return (
<img src={this.props.buttonImgSrc}></>
);
}
});
var LimitedInputBox = React.createClass({
render: function() {
return (
<Title labelText={this.props.data.labelText} />
<InputBox
hinderText={this.props.data.hinderText}
regExp={this.props.data.regExp}
/>
<ClearButton buttonImgSrc={this.props.data.buttonImgSrc} />
);
}
});
ReactDOM.render(
<LimitedInputBox data={data} />,
document.getElementById('example')
);
/** author : river he**/
//粗划分
var data = {
labelText: "酒店地址",
hinderText: "请填写酒店地址",
buttonImgSrc: "eliminate.png",
regExp: /^\w{5,8}$/
};
var LimitedInputBox = React.createClass({
render: function() {
return (
<div>
<label >{this.props.data.labelText}</label>
<input
placeholder={this.props.data.hinderText}
regExp={this.props.data.regExp}>
</input>
<img src={this.props.buttonImgSrc ></img>
</div>
);
}
});
ReactDOM.render(
<LimitedInputBox data={data} />,
document.getElementById('example')
);
为了使 UI 可交互,需要能够触发底层数据模型的变化。 React 通过 state 使这变得简单。
为了正确构建利用,首先需要斟酌利用需要的最小的可变 state 数据模型集合。此处关键点在于精简:不要存储重复的数据。构造出绝对最小的满足利用需要的最小 state 是有必要的,并且计算出其它强烈需要的东西。
本案例较简单,state
很明显是inputText
,即input
输入框中的值。
而对1般情况,可以简单地对每项数据提出3个问题:
- 是不是是从父级通过props传入的?如果是,可能不是state。
- 是不是会随着时间改变?如果不是,可能不是state。
- 能够根据组件中其他的state数据或props计算出来吗?如果是,就不是state。
找出了state
以后,需要继续找出那些组件会被state
更新,即哪些组件应当具有state
数据模型,本案例一样很简单,由于输入框input
要判断用户输入是不是符合正则表达式要求,因此与input
相干的组件都应当具有state
。依照第1种细分,InputBox
组件应当具有state
,依照第2个细分,由于只存在1个组件LimitedInputBox
,故其应当具有state
。
//细分结构
var data = {
labelText: "酒店地址",
hinderText: "请填写酒店地址",
buttonImgSrc: "eliminate.png",
regExp: /^\w{5,8}$/
};
var Title = React.creatClass({
render: function() {
return (
<label>{this.props.labelText}</label>
);
}
});
var InputBox = React.createClass({
render: function() {
return (
<input
placeholder={this.props.hinderText}
value={this.props.inputText}
regExp={this.props.regExp}>
</input>
);
}
});
var ClearButton = React.createClass({
render: function() {
return (
<img src={this.props.buttonImgSrc}></>
);
}
});
var LimitedInputBox = React.createClass({
getInitialState: function() {
return {
inputText: ''
};
},
render: function() {
return (
<Title labelText={this.props.data.labelText} />
<InputBox
hinderText={this.props.data.hinderText}
inputText={this.state.inputText}
regExp={this.props.data.regExp}
/>
<ClearButton buttonImgSrc={this.props.data.buttonImgSrc} />
);
}
});
ReactDOM.render(
<LimitedInputBox data={data} />,
document.getElementById('example')
);
/** author : river he**/
//粗划分
var data = {
labelText: "酒店地址",
hinderText: "请填写酒店地址",
buttonImgSrc: "eliminate.png",
regExp: /^\w{5,8}$/
};
var LimitedInputBox = React.createClass({
//初始化state
getInitialState: function() {
return {
inputText: ''
};
},
render: function() {
return (
<div>
<label >{this.props.data.labelText}</label>
<input
placeholder={this.props.data.hinderText}
regExp={this.props.data.regExp}
value={this.state.inputText}
></input>
<img
src={this.props.data.buttonImgSrc}
</img>
</div>
);
}
});
ReactDOM.render(
<LimitedInputBox data={data} />,
document.getElementById('example')
);
前面构建了渲染正确的基于props
和state
的沿着组件树从上至下单项数据活动的利用。然后我们需要构建反向的数据活动方式:组件树中层级很深的表单组件更新父级中的state
。
如果尝试在前面的输入框中输入,React会疏忽你的输入。这是成心的,由于已设置了input
的value
属性,使其总是和LimitedInputBox
(对粗分的情况,就是其本身)传递过来的state
1致。
但是我们希望的是,不管用户什么时候改变了表单,都要更新state
来反利用户的输入。由于组件只能更新自己的state
,LimitedInputBox
将会传递1个回调函数给InputBox
,此函数将会在state
应当被改变时触发。我们可使用input
的onChange
事件来监听用户输入,从而肯定什么时候触发回调函数。
LimitedInputBox
传递的回调函数将会调用setState()
,然后利用将会被更新。
/**author : River He*/
//细分结构
var data = {
labelText: "酒店地址",
hinderText: "请填写酒店地址",
buttonImgSrc: "eliminate.png",
regExp: /^\w{5,8}$/
};
var Title = React.createClass({
render: function() {
return (
<label>{this.props.labelText}</label>
);
}
});
var InputBox = React.createClass({
handleChange: function() {
this.props.onUserInput(
this.refs.inputBox.value
);
},
fitRegExp: function(inputText) {
if(inputText.match(this.props.regExp) != null) {
// console.log("true");
return true;
} else {
// console.log("false");
return false;
}
},
render: function() {
return (
<input
style={this.fitRegExp(this.props.inputText)?({border: '1px solid green'}):({border: '1px solid red'})}
placeholder={this.props.hinderText}
value={this.props.inputText}
regExp={this.props.regExp}
ref="inputBox"
onChange={this.handleChange}>
</input>
);
}
});
var ClearButton = React.createClass({
handleClick: function() {
this.props.onClear();
},
render: function() {
return (
<img
src={this.props.buttonImgSrc}
onClick={this.handleClick}
/>
);
}
});
var LimitedInputBox = React.createClass({
getInitialState: function() {
return {
inputText: ''
};
},
handleUserInput: function(inputText) {
this.setState({
inputText: inputText
});
},
handleClear: function() {
this.delText();
},
getText: function() {
return this.state.inputText;
},
setText: function(text) {
this.setState({
inputText: text
});
},
delText: function() {
this.setState({
inputText: ''
});
},
render: function() {
return (
<div>
<Title labelText={this.props.data.labelText} />
<InputBox
hinderText={this.props.data.hinderText}
inputText={this.state.inputText}
regExp={this.props.data.regExp}
onUserInput={this.handleUserInput}
/>
<ClearButton
buttonImgSrc={this.props.data.buttonImgSrc}
onClear={this.handleClear}
/>
</div>
);
}
});
ReactDOM.render(
<LimitedInputBox data={data} />,
document.getElementById('example')
);
/** author : river he**/
//粗分结构
var data = {
labelText: "酒店地址",
hinderText: "请填写酒店地址",
regExp: /^\w{5,8}$/
};
var LimitedInputBox = React.createClass({
//初始化state
getInitialState: function() {
return {
inputText: ''
};
},
// handleKeyUp: function(inputText) {
// this.setState({
// inputText: this.refs.input.value.trim()
// });
// },
//处理输入框变化
handleChange: function() {
this.setState({
inputText: this.refs.input.value.trim()
});
},
//处理删除事件
handleClear: function() {
this.delText();
},
//删除方法
delText: function() {
// console.log(this.refs.input.text);
this.setState({
inputText: ''
});
},
//获得用户输入
getText: function() {
return this.state.inputText;
},
//设置输入框内容
setText: function(text) {
this.setState({
inputText: text.trim()
});
},
//判断输入内容否符合设置的正则表达式
fitRegExp: function(inputText) {
// console.log("start fitRegExp");
if(inputText.match(this.props.data.regExp) != null) {
// console.log("true");
return true;
} else {
// console.log("false");
return false;
}
},
render: function() {
return (
<div>
<label >{this.props.data.labelText}</label>
<input
style={this.fitRegExp(this.state.inputText)?
({border: '1px solid green'}):({border: '1px solid red'})}
placeholder={this.props.data.hinderText}
regExp={this.props.data.regExp}
// onKeyUp={this.handleKeyUp}
onChange={this.handleChange}
value={this.state.inputText}
ref='input'
></input>
<img src="eliminate.png" onClick={this.handleClear}></img>
</div>
);
}
});
ReactDOM.render(
<LimitedInputBox data={data} />,
document.getElementById('example')
);
以上就是1个简单的输入框组件,相应的html模板和css以下,没有甚么样式,希望读者体谅,有时间改下css。
<!-- limitedInputBox.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF⑻">
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
<!-- <script type="text/babel" src="http://www.wfuyu.com/upload/caiji/20160629/limitedInputBox.js"></script> -->
<script src="inputWidget.js" type="text/babel"></script>
<link rel="stylesheet" href="limitedInputBox.css">
<title>LimitedInputBox</title>
</head>
<body>
<div id="example"></div>
</body>
</html>
//limitedInputBox.css
img {
height: 14px;
width: 14px;
}
JS Bin on jsbin.com