写了一段时间的前端和 React Native,感觉刚刚摸到一些门道,所以想写一些东西,来记录一下自己的学习过程。由于几个项目主要用的还是 React 体系的东西,且不同项目状态管理的方式不断演进,所以打算以 React 的状态管理为主线,来记录这一过程。
这个系列会从 React 最基本的 state/prop 开始介绍,一直延展到 、、、 等框架,其间会扩展相关的知识点,如 React 生命周期、js中的函数式编程、中间件、生成器等,还可能会有些源码分析等。每篇文章不会太长,讲清楚一个点即止,慢慢写。如有不对或疑问之处,欢迎指正或讨论。
本文难易度:★☆☆☆☆
正好有小伙伴给推荐了 The React State Museum ,也一并学习了。
组件、JSX 和 render
这里我们只是简单介绍一下这几个概念,因为它们是我们状态管理的基石。
Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.
在 React 中,所有界面的结构组织及展示都是基于组件的。而组件的渲染操作是在组件的 方法执行的。React 更倾向于通过组合的方式来创建一个组件,而非继承的方式。一个页面也是组件层层嵌套组合而成。
为了让组件的 UI 结构及渲染逻辑更好地与业务逻辑相分离,并且让 UI 更贴近 ,React 使用了 语法来创建组件的 UI 结构(),下面是一个 JSX 的例子:
// React
constelement = (
Hello, world!
);
// React Native
exportdefaultclassHelloWorldAppextendsComponent{
render() {
return(
Hello world!
);
}
}
JSX 让整个页面的 UI 代码更加友好和易读。
Props
一个组件可由多个子组件构成。组件的层级结构构成了整个页面的框架。我们通常都会有这样的需求,即在父组件中去控制子组件的一些特性,比如样式、显示的文本、数值信息等。如何来处理呢?
如果你了解 HTML,会知道一个标签会有很多属性,比如一个 img 标签:
React 组件也为我们提供了类似的特性,即 。我们先以一个简单的 React 展示组件为例:
functionAvatar(props){
const{ url, height, width } =this.props;
return(
)
}
function User() {
const url = 'https://tva1.sinaimg.cn/crop.1.0.1366.1366.180/c5ff030ejw8f5bbc70i61j212011yq80.jpg';
return (
)
}
是一个组件,其接受 3 个属性输入,即 、、,我们在父组件 中,创建 Avatar 时,可以为其设置属性值,从而控制 Avatar 组件的显示。而在 Avatar 组件内部,我们可以通过 来获取到属性对象集,并从中抽取出想要的属性。
在 React Native 中也一样,如 组件:
exportdefaultclassBananasextendsComponent{
render() {
letpic = {
uri:'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg'
};
return(
);
}
}
需要注意的是, 是不可变,如果我们在子组件中尝试更改 props 属性,React 会给出错误警告。
如果想对属性进行类型检查并且给其设置默认值的话,可以借助 库。具体可以查看facebook/prop-types。
父子组件间传值的方式
实际上,从上面可以看到,父组件通过 props 向子组件传递了一些数据。也就是说,父子组件可以通过 props 来进行通信。不过上面的数据传递是从父组件到子组件,那如果想从子组件向父组件传递数据,比如说在一个列表中点击某个单元格,我需要知道点击的是哪个单元格的索引,那应该怎么处理呢?
这时候我们依然需要借助于 props ,只不过我们可以从父组件传递一个函数给子组件,我们可以称之为。我们来看一个 React Native 的 FastList 的示例:
classMyListItemextendsReact.PureComponent{
_onPress =()=>{
this.props.onPressItem(this.props.id);
};
render() {
consttextColor =this.props.selected ?"red":"black";
return(
);
}
}
classMultiSelectListextendsReact.PureComponent{
state = {selected: (newMap():Map)};
_keyExtractor =(item, index) =>item.id;
_onPressItem =(id: string) =>{
// updater functions are preferred for transactional updates
this.setState((state) =>{
// copy the map rather than modifying state.
constselected =newMap(state.selected);
selected.set(id, !selected.get(id));// toggle
return;
});
};
_renderItem =() =>(
id=
onPressItem=
selected={!!this.state.selected.get(item.id)}
title=
/>
);
render() {
return (
data=
extraData=
keyExtractor=
renderItem=
/>
);
}
}
在这个例子中,我们在点击 时,会调用 方法,在这个方法中调用了输入属性 ,并将 属性作为参数传递给 onPressItem 方法。而 onPressItem 回调函数正是父组件 中创建 MyListItem 时传递给 MyListItem 的。
由此可以看出父子组件完全可以通过 props 来进行通信。当然这就涉及到另外两个问题:
跨层级组件之间如何通信?
兄弟结点之间如何通信?
领取专属 10元无门槛券
私享最新 技术干货