React 状态管理:从 props和state 说起

写了一段时间的前端和 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 来进行通信。当然这就涉及到另外两个问题:

跨层级组件之间如何通信?

兄弟结点之间如何通信?

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180530G06RN800?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码关注腾讯云开发者

领取腾讯云代金券