© fengyu学习
本系列原本已经打算太监了,但是今早的app销量触动了我,给了我一个正向激励。
重读了一遍代码,决定继续和大家分享React-Native的实践,聊一下组件之间的通信,使用TextInput组件碰到的坑,和一些上架的体会。
1、组件间的通讯
- App入口组件 ShikigamiBox.js
export default class ShikigamiBox extends Component {
constructor(props) {
super(props);
this.state = {
searchResult: ""
}
}
render() {
return (
<View style={styles.container}>
<ShikigamiHeader/>
<ShikigamiSearch filterShikigamiList={this.filterShikigamiList} />
<ShikigamiListView showFengyinResult={this.showFengyinResult} filterName={this.state.filterName} />
<ShikigamiModel clearSearchResult={this.clearSearchResult} content={this.state.searchResult} />
</View>
);
}
showFengyinResult = (searchResult) => {
this.setState({
searchResult
})
}
clearSearchResult = () => {
this.setState({
searchResult: ""
})
}
filterShikigamiList = (filterName) => {
this.setState({
filterName
});
}
}
- 搜索框 ShikigamiSearch.js
export default class ShikigamiSearch extends Component {
constructor(props) {
super(props);
this.state = {
text: ""
};
}
handleChangeText = (text) => {
setTimeout(() => {
this.props.filterShikigamiList(text);
this.setState({
text
});
}, 50);
}
render() {
return (
<View style={styles.container}>
<TextInput style={styles.input}
placeholder="请输入首字母或式神名"
onChange={(evt) => this.setState({ text: evt.nativeEvent.text })}
onChangeText={this.handleChangeText}
onEndEditing={(evt) => this.setState({ text: evt.nativeEvent.text })}
value={this.state.text}
/>
</View>
);
}
}
React-Native
和 React
一脉相承,都是依靠 state
和 props
来做到组件的通信以及自身渲染的管理的,比如上面实现的这段代码。
-
ShikigamiSearch
输入框监听了onChangeText
事件 -
ShikigamiSearch
调用this.props.filterShikigamiList({$输入的文本})
-
ShikigamiBox
组件调用this.filterShikigamiList()
改变state
中的filterName
,触发render()
- 因为
ShikigamiListView
组件以this.state.filterName
作为props
,所以触发了componentWillUpdate()
- 此处有业务方法实现过滤数据,并改变
ShikigamiListView
的state
中的dataSource
-
ShikigamiListView
中展示出过滤后的最新列表
2、面向对象的思想
那段时间一直在为了面向对象而面向对象,这个作品算是一个很明显的体现。
ShikigamiBean.js
- name(名称)
- level(等级)
- logo(图标)
- initial(首字母)
- clue(线索)
import {log} from "../utils/common";
const baseParams = ['name', 'icon'];
export default class ShikigamiBean {
constructor(shikigami) {
for (let i = 0, l = baseParams.length; i < l; i++) {
let bp = baseParams[i];
if (!shikigami[bp]) {
log('式神属性缺失,初始化失败,缺失属性为:"' + bp + '"');
throw new Error("10000");
}
}
this.name = shikigami.name;
this.level = shikigami.level;
this.icon = shikigami.icon;
this.initial = shikigami.initial;
this.clue = shikigami.clue;
}
}
ShikigamiList.js
最重要的是里面的filter()
方法,确实让过滤式神列表变得十分的清晰
- A - Z 匹配首字母
- 首个字模糊匹配
- 整个名字精准匹配
- 利用线索进行匹配
import ShikigamiBean from "./ShikigamiBean";
import {log} from "../utils/common";
// 普通式神列表
const COMMON = "commonList";
// 依据首字母进行分类的式神列表
const SORTBYINITIAL = "sortByInitialList";
export default class ShikigamiList {
initData;
commonList = [];
sortByInitialList = new Set();
constructor(data) {
this.initData = data;
data.forEach((shikigami, index) => {
try {
this.commonList.push(new ShikigamiBean(shikigami));
} catch (e) {
log('第' + index + '位的式神初始化失败!');
}
});
this.sortByInitial();
}
// 使用首字母对list中数据进行分类
sortByInitial() {
this.commonList.forEach((shikigami, index) => {
let initial = shikigami.initial,
sortByInitialList = this.sortByInitialList;
if (!sortByInitialList[initial]) {
sortByInitialList[initial] = [shikigami];
} else {
sortByInitialList[initial].push(shikigami);
}
});
}
filter(value) {
if (!value) return this.sortByInitialList;
if (/[A-Z]/i.test(value.charAt(0))) {
const filterInitial = value.charAt(0).toUpperCase();
const result = this.sortByInitialList[filterInitial];
if (result) {
return {[filterInitial]: result};
}
}
let matchInitial = "";
let matchShikigamiArr = [];
let clueShikigamiArr = [];
for (let shikigami of this.commonList) {
if (shikigami.name.charAt(0) === value.charAt(0)) {
if (shikigami.name === value) {
return {[shikigami.initial]: [shikigami]};
} else {
if (!matchInitial) {
matchInitial = shikigami.initial;
}
matchShikigamiArr.push(shikigami);
}
}
// 线索查询
if(shikigami.clue && shikigami.clue.indexOf(value) > -1) {
var copyShikigami = Object.assign({}, shikigami);
copyShikigami.clueShow = true;
clueShikigamiArr.push(copyShikigami);
}
}
var returnList = {};
if (matchInitial) {
returnList[matchInitial] = matchShikigamiArr;
}
if (clueShikigamiArr.length > 0) {
returnList['线索'] = clueShikigamiArr;
}
return returnList;
}
get(key) {
return this[key];
}
}
export {
COMMON,
SORTBYINITIAL
}
3、TextInput组件使用的坑
印象比较深刻的是中文输入法在输入框中输入的时候,无法及时获取到输入的字母。
解决方法(自带输入法没问题了,其他的待验证)
-
onChange
方法设置(evt) => this.setState({ text: evt.nativeEvent.text })
-
onEndEditing
方法设置(evt) => this.setState({ text: evt.nativeEvent.text })
参考文章:React Native 中 TextInput 组件和中文输入冲突
<TextInput style={styles.input}
placeholder="请输入首字母或式神名"
onChange={(evt) => this.setState({ text: evt.nativeEvent.text })}
onChangeText={this.handleChangeText}
onEndEditing={(evt) => this.setState({ text: evt.nativeEvent.text })}
value={this.state.text}
/>
4、关于App的上架
本来当时有挺多体会的,个人心情是多于查流程,走流程。可能应用比较简单吧,所以上架审核的时间都挺快的。
由于时间比较久远,真的不记得为什么被拒了,好像有一次是2个名称不一致导致的,第二次就上线的很顺利了,不过由于这是个单机应用,几乎没有用到权限,所以可能审核比较宽松。
还记得用英语和审核人员沟通被拒的原因时,那种忐忑的感觉。
5、开源
希望这个代码可以对有些朋友有帮助,如果有热心人完善了数据,或者增强了功能,可以私聊我,我可以帮忙上架。