官方的 Quick start https://facebook.github.io/react/docs/hello-world.html

React 设计思想 https://github.com/react-guide/react-basic

React 技术栈系列教程 http://www.ruanyifeng.com/blog/2016/09/react-technology-stack.html

深入浅出React http://www.infoq.com/cn/dive-into-react

React 的核心思想是:封装组件。 各个组件维护自己的状态和 UI,当状态变更,自动重新渲染整个组件。 基于这种方式的一个直观感受就是我们不再需要不厌其烦地来回查找某个 DOM 元素,然后操作 DOM 去更改 UI。基于这些概念:组件,JSX,Virtual DOM,Data Flow

  • 组件

React 应用都是构建在组件之上。

上面的 HelloMessage 就是一个 React 构建的组件,最后一句 render 会把这个组件显示到页面上的某个元素 mountNode 里面,显示的内容就是 <div>Hello John</div>

props 是组件包含的两个核心概念之一,另一个是 state。可以把 props 看作是组件的配置属性,在组件内部是不变的,只是在调用这个组件的时候传入不同的属性(比如这里的 name)来定制显示这个组件。

  • JSX

从上面的代码可以看到将 HTML 直接嵌入了 JS 代码里面,这个就是 React 提出的一种叫 JSX 的语法,这应该是最开始接触 React 最不能接受的设定之一,因为前端被“表现和逻辑层分离”这种思想“洗脑”太久了。但实际上组件的 HTML 是组成一个组件不可分割的一部分,能够将 HTML 封装起来才是组件的完全体,React 发明了 JSX 让 JS 支持嵌入 HTML 不得不说是一种非常聪明的做法,让前端实现真正意义上的组件化成为了可能。

好消息是你可以不一定使用这种语法,后面会进一步介绍 JSX,到时候你可能就会喜欢上了。现在要知道的是,要使用包含 JSX 的组件,是需要“编译”输出 JS 代码才能使用的,之后就会讲到开发环境。

  • Virtual DOM

当组件状态 state 有更改的时候,React 会自动调用组件的 render 方法重新渲染整个组件的 UI。

当然如果真的这样大面积的操作 DOM,性能会是一个很大的问题,所以 React 实现了一个Virtual DOM,组件 DOM 结构就是映射到这个 Virtual DOM 上,React 在这个 Virtual DOM 上实现了一个 diff 算法,当要重新渲染组件的时候,会通过 diff 寻找到要变更的 DOM 节点,再把这个修改更新到浏览器实际的 DOM 节点上,所以实际上不是真的渲染整个 DOM 树。这个 Virtual DOM 是一个纯粹的 JavaScript 数据结构,所以性能会比原生 DOM 快很多。

  • Data Flow

“单向数据绑定”是 React 推崇的一种应用架构的方式。当应用足够复杂时才能体会到它的好处,虽然在一般应用场景下你可能不会意识到它的存在,也不会影响你开始使用 React,你只要先知道有这么个概念。

单向数据流 Unidirectional data flow

简单来说单向数据流就是确保数据是单向绑定的,例如下图,数据的更新永远是顺着一个方向而不能反过来。

http://www.infoq.com/cn/articles/react-art-of-simplity

react-data-flow

比较Angular.js的安逸双向绑定模式,React.js 中 Action 如果要刷新 View,Action 需要调用 setState 来修改model,然后View会自动刷新(重新运行 render 方法)。View上的修改则和Action完全没有绑定:需要onChange方法(否则 Input 是只读的,当然事先设置了 value=${model})来显式得到input里的值。而在 Angular.js 一行 JavaScript 代码也不需要。显然,React需要用新的开发模式。

“常用的模式是创建多个只负责渲染数据的无状态(stateless)组件,在它们的上层创建一个有状态(stateful)组件并把它的状态通过 props 传给子级。这个有状态的组件封装了所有用户的交互逻辑,而这些无状态组件则负责声明式地渲染数据。” http://reactjs.cn/react/docs/interactivity-and-dynamic-uis.html

我原来对Dojo的分析 http://fkpwolf.net/2010/03/04/from-embed-data-in-html-to-dojo-component-mode/

从TODOMVC看,https://github.com/tastejs/todomvc/blob/gh-pages/examples/react/js/app.jsx 他是把显示和逻辑混合在一起,没有angular.js无比高级的html自定义标签,这和我们一般分离的思想格格不入。其实angular.js也是混合的,它的模板就是逻辑语言。

这货warning.js功能很强,很多错误都能提示出来,开发者体验不错。

组件每个页面都是组件,而小的控件也是组件。不像 Angular.js 那样用用 ui-view 和 directive 来区分,这样开发更统一了。这点来说更像Dojo,当然,他创建widget是直接用 这种方式,更直观,更容易重用。

React.js 组件也会有些不同,容器组件和展示组件 http://www.jianshu.com/p/6fa2b21f5df3 展示组件不定义数据来源,容器组件包含展示组件,但是不包含 DOM 和 CSS。Dva的组件设计方法,容器组件才会 connect redux。

React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. https://facebook.github.io/react-native/ 优点在于既有 js/css 开发的遍历,也会编译成 native ios/android 的代码,纯原生,而且开发的时候可以不用编译,即时修改即时显示(和 web 开发一样)。也可以调用已有的原生代码。缺点在于他如何抹平 ios/andorid 的区别,毕竟这两大平台之间的竞争必然导致差异性。那和 Hybrid App 区别呢?混合应用追求的是快速发布,本地应用更多是性能和极致体验的考虑。阿里也搞了个 Weex,其实就是 vue-native。

props与sate的区别 React 基于状态实现对DOM控制和渲染。组件状态分为两种:一种是组件间的状态传递、另一种是组件的内部状态,这两种状态使用props和state表示。props用于从父组件到子组件的数据传递。组件内部也有自己的状态:state,这些状态只能在组件内部修改。

JSX 里面不能包含 if, foreach,因为 jsx 只是方法调用,你不能把 if 放到里面。https://stackoverflow.com/questions/22876978/loop-inside-react-jsx 这个就导致 JSX 不是很灵活,一种解决方法是方法体外计算好变量,然后把变量传给 jsx。但是对于 list.map 里面的就很无奈了。这逼迫你创造很多小的组件?

你没法在JSX中使用 if-else 语句,因为 JSX 只是函数调用和对象创建的语法糖(jsx 会编译成一句超长 js 语句,这是函数式特点)。只能用三元操作符来搞。这样 JSX 局限不是很大么?https://facebook.github.io/react/docs/conditional-rendering.html 其实只是官方没有 ng-if 这种组件,有些第三方的会有,但显然官方还是推荐用 js 的语言来。

组件

Stateless 组件本身如何包含 state 呢?比如简单的toogle功能都没法实现了吧?状态由 parent 的有状态组件维护或者使用 Redux。

分成这么多小组件,意义何在?重用场合并不多。层次更分明,每个组件代码不会太长,因为他包含了很多其他的组件。

更多是包装 wrap 模式。页面元素更独立,修改起来容易。总的来说是隔离的思想。

有了组件后,任何调用/传递都是函数式的,也有了组件的生命周期的控制。比如 list.map( return <MyComponent />),这个如果写在 js 里面或者像 Angular.js 的 ng-repeate,就缺少了组件值传递的控制,比如我想优化这个列表的性能,当传值不变时不重画(这个优化不是必须的),这里独立组件就有必要了。

react-component

react-lifecycle

官网 https://reactjs.org/docs/faq-ajax.html 推荐在 componentDidMount 里面调用 ajax。

state变化是因为调用了 setState,React 是如何知道 Props 发生了变化呢?

Stateless

对于 Stateless Component,如果有内部的状态,而这个状态只是自己用,怎么办?强制让使用者自己传有点莫名其妙。这里介绍了 recompose 库:

export default composeWithState({ text: '' })(TextBox); 

这个创建了临时的状态,免去了用 Redux 的繁琐的创建新文件新 action。但是这个 state 改变时 Stateless Component 并不会重绘,这样有个毛用。原来它还注入了一个 setText 的方法来改变 state,直接赋值是不行的。这就有点像一个简易化的能生成部分代码的 Redux 了。这个 text state 能否作为默认的/可选的,当有外部传入时使用外部的方法。

Noe4j Browser 里面使用 preact-suber withBus来附加属性:

export default withBus(connect(mapStateToProps, mapDispatchToProps)(App))

Stateless 也不是万金油 https://hackernoon.com/react-stateless-functional-components-nine-wins-you-might-have-overlooked-997b0d933dbc

但是 Stateless 才是函数式的精华,配合 ES6,甚至都不需要定义 class。但是对于 UI 来说,状态总是无处不在的。

性能

React 渲染机制解析 http://imweb.io/topic/5985cc4d35d7d0a321c5eb75 有讲Diff算法

什么时候要在React组件中写shouldComponentUpdate? http://www.infoq.com/cn/news/2016/07/react-shouldComponentUpdate 一般情况下没有必要写,因为默认的 render 即使被调用,还会和上次的返回值对比(纯的 json 比较),如果一致,就不会更新界面中的DOM,而这个diff算法是很高效的,节省的这点diff算法时间人不容易察觉。

官方的性能描述 https://facebook.github.io/react/docs/optimizing-performance.html PureComponent 会有个自带实现 shallow comparison,避免了自己写 shouldComponentUpdate,但是因为是浅比较,所以需要 Immutable.js 或者 Object.assign 或者 ES6 展开语法,这样让每次修改后得到是新的对象,而老对象保持不变。

深度剖析:如何实现一个 Virtual DOM 算法 https://github.com/livoras/blog/issues/13 (非 Shadow DOM)

项目中用到了云图,一个列表里面包含了10个云图。数据获取很快但是渲染很慢。我在云图组件里面使用了timeout来延时渲染,这样列表会先出来,然后再显示云图。虽然可以工作,但是timeout让代码难于理解。

数据可视化 这里面也有讨论图表这种特殊组件的性能

样式

组件封装后,style 就难修改了,除非这个组件接受style props。但是假设我只是想细微的修改而已,这个就有点麻烦了。暂时想到的是在外面包一个<div className={styles.aDivClass} />,但是只能针对这个div,对于div里面的好像无法在less/sass用 .aDivClass bDivClass 这样方式嵌套样式。style= 则只能inline的方式编辑。这样做是为了隔离 css,和 web component 类似。找到办法:在.aClass 外面套上一层:global {},这样里面的 .aClass 在 webpack 编译的时候就不会变成 .aClass_2w3a4 这样的名字( HTML element like span 不会变)。

组件封装了 css 这样让测试变为可能,所以 css 不能随便变化。但是对于一个组件库,如果小改变改如何处理呢?扩展?

https://www.styled-components.com/ 这个则是把 css class 直接包装成一个组件,Neo4j 就这样搞的。不是很优雅。但满足了 React 的哲学,方便单元测试。与其定制 css,不如搞个新的 wrap 组件?重要的是其把定制这个工作给封装了起来。这种叫CSS-in-JS。

Inline style 一般的 HTML 元素可以用 <div style=> 这种奇怪的方式做标注,但是对于自定义组件,如果对其使用 style,默认是不生效的(ant Button 可以,但是其非一般的 extent Component),需要使用 …style 方式引入。

Redux/Flux

架构入门教程 http://www.ruanyifeng.com/blog/2016/01/flux.html

Flux的经典数据流:

react-flux

http://cn.redux.js.org/index.html Redux 中文文档

https://github.com/reactjs/redux/tree/master/examples/todomvc

http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html Redux 入门教程(一):基本用法

http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html Redux 入门教程(二):中间件与异步操作

http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_three_react-redux.html Redux 入门教程(三):React-Redux 的用法

对于我来说,最直接的好处是给React提供一个类似Angular service这种全局变量的地方,这样页面跳转和组件变化时仍能有个共享变量的地方。

这东西和 Dojo 的 event 一样么?只是个消息的发送和订阅?

https://github.com/reactjs/redux/blob/master/docs/introduction/Examples.md 里没有TodoMVC,不过不是官方的。

cdap-ui 中,SchemaTable/index.js 使用 connect(mapStateToProps, mapDispatchToProps)(FieldRow) 这种方式来创建组件,这个是上面的 Redux 入门教程(三):React-Redux 的用法 里面的方式。外面的 <Provider store={store}> 会把 store 注入到 context,然后 connect 会把 context 里面的值转为 props 传给 FieldRow,否则 FieldRow 要拿到特定的 context,必须显示的声明 childContextTypes,这种方式是官方不推荐的。context 是 React 的概念,context 会从父组件传到子组件。

Neo4j/src/routes/query/CypherFrame/index.jsx,这个用connect转换map到props,但是自己也用到了state,这样有何意图?有点混乱啊。这个 this.state 是组件自己维护的 state,和 store 传过来的两码事。用了这个connect,那这样就不用传props给组件了,组件自己去connect?但是我看到neo4j里面props是大量传递的。

通过属性 a connect了组件A,如果a发生变化,则A会自动刷新。参考Ant Design里面的resize处理方式。

组件A包含B,A把this.state.a作为一个属性传给B。如果A用setState修改了a,则B会重画。这个是官方React的功能,效果和上面的Redux差不多。那为什么要发明Redux呢?避免混乱的setState?

这种实际上是个观察者模式了,但是比起Dojo的emit/subscribe,这个更直观,数据范围更大。而且把消息的处理代码统一到一个位置,体现了真正的独立的全局数据模型。相比较 Angular.js 只关注当前页面的数据模型分离,虽然对于 SPA 来说这个问题不大,但是 SPA 并非只有一个页面,页面间的数据传递量比较大。

Dva 里面是采用 connect((mailAlert) => (mailAlert))(Alert) 这种更直接的方式。mailAlert 是在 router 里面使用 registerModel(app, require('models/mailAlert’)) 来定义的,名字并不重要。

Redux 中间件 另外条目

React + Mobx,http://cn.mobx.js.org/,据说更轻量级,有被 Vue 使用。

mobx vs redux

  • 相似点
    • 作用是一样的,均用于state的管理
    • 数据流动均是单向的
  • 不同点
    • store:redux是单个store,mobx可以是多个
    • 数据结构:redux使用正常的javascript对象,而mobx进行包裹,得到observable数据
    • immutable:redux要求数据的不可变形,而mobx则不坐要求
    • action:redux通过action来驱动数据的变化,是必选项,而mobx则为可选项
    • 代码量:mobx代码量小,可以快速完成简单业务开发
    • 耦合性:redux耦合度低,可以便于复用,也方便进行单元测试
    • 生态环境:redux的生态环境优于mobx
    • 使用场景:mobx适用于简单的业务,快速完成开发;redux适用于复杂场景

UI 组件库

https://draftjs.org/ Facebook 官方的文本编辑器,据说底子好,容易在上面二次开发

https://facebook.github.io/fixed-data-table/ 官方的datagrid

Ant Design

https://github.com/react-component

https://juejin.im/entry/5b3f3c82e51d45190905d3a2 28个顶级的React UI组件库,请查收!

动画

https://reactjs.org/docs/animation.html

https://medium.com/@bjorn.holdt/react-animations-101-css-transitions-9c1050c2bc9d 本以为如果修改了 className,DOM 会重建,然后动画就没法继续了,这里看来 React 并没有做重建,所以 CSS 动画还是一样可以用。

测试

组件分的如此之散,redux, rx.js,这么多的组件,如果没有单元测试,要打通一条路径页面得不断的修改和改进,每次测试都需要点下浏览器,这个效率很低(还是我刚开始上手所以效率低?)。

https://facebook.github.io/jest/docs/en/getting-started.html Jest 也是 facebook 提出的测试框架。除了一般的 DOM 测试,也提供了 snapshot testing,这个是第一次运行会生成 snapshot,也就是渲染出来的 HTML 结果,然后第二次会和第一次生成的对比,如果一样则通过。这样写 test 就不用一个个比较 dom 了。如果需求和样式改了则需要手动生成新的 snapshot。Neo4j-Browser 大多是传 props 给 component 看 有没有报错而已。

Ant design 大量使用了 Enzyme来做 DOM 测试,其也可以模拟 click 事件。http://facebook.github.io/jest/docs/zh-Hans/tutorial-react.html#content 官方的 DOM 测试文档。总觉得是聊胜于无的东西。其组件代码都是 TypeScript 写的,这个帮助可能更大,因为组件现在都是属性传入(connect/redux 可能会破坏这个),而且声明了 PropTypes,加上 typescript,效果更好。但是这个对于写组件、接口这种比较稳定的代码肯定有益,对普通项目有帮助么?

https://flow.org/en/docs/getting-started/ https://facebook.github.io/react/docs/typechecking-with-proptypes.html Type Check 这个默认不是强制的,也只有在 eslint 才会报错。props type mismatch 开发时会报错。可能对 typescript 会有帮助。

Majestic is an electron app for running tests with Jest. Majestic is a tool built for providing great developer experience when you write tests with Jest.

工具

React & Redux 都有各自的 Chrome 插件

https://github.com/facebookincubator/create-react-app Facebook官方脚手架,最小化的依赖,但是也可以自动刷新页面。

react-error

这都能发觉,太厉害了。其开发者体验不错。

VS Code https://marketplace.visualstudio.com/items?itemName=xabikos.ReactSnippets 用快捷键创建一些 React Component。

React.js in CDAP

react-cdap

比如首页的实体列表,cdap-ui/app/cdap/components/EntityListView/ListView/index.js,这个里面会使用另外一个 component EntityCard,不同的 card 比如 pipeline 或者 dataset,没有使用继承的方式,包含?一个 card 分为总的 card,header,status/metrics 和最下面的 fast action。只有 metrics 有各种类型如 DatasetMetrics、DatasetMetrics,而实例化也没有用 Factory 模式,用的 if-else。FastActions 包含不同类型的 Action 的列表,比如 SendEventAction、ExploreAction。如果这些 component 重用性很高,这种分散的编程模式灵活性会很好,缺点就是复杂度。而 UI 重用一般很少,我觉得这样的好处在于代码的清晰。不知道这种嵌套、包含的方式对布局是否有影响。

和 Angular.js 的 directive 比较,component 出现的更频繁。

如果 component 能像原生 HTML Tag 那样容易使用,看上去别无二致就好了。但个人还是偏向一切都用原生的 tag,表现更为自然。

这种 component 对于大项目怎么样?重用能提高大项目的内聚性,分离能隔离复杂性。但是如此多的 component 管理和调试起来会很头痛吧。

修改某个 component 文件后,

Hash: 2334fb67c3ec2226f619 
Version: webpack 1.13.2 
Time: 21417ms 
        Asset     Size  Chunks             Chunk Names 
    ./cdap.js   4.9 MB       0  [emitted]  cdap 
./cdap.js.map  4.33 MB       0  [emitted]  cdap 
[WEBPACK 16:47:30] Finished building ./cdap.js within 21.417 seconds 

livereload 有起作用但是是整个页面刷新,而且还耗时21秒!!!为什么开发模式也要合并编译?

看来 4.1 的 React 还是刚开始开发,诸多不成熟。

Router / 路由 cdap-ui/app/cdap/components/Home/index.js

在 jsx 里面嵌入 <Match exactly pattern="/ns/:namespace" component={EntityListView} />,真是一个好点子。

https://spin.atomicobject.com/2014/04/03/combinelatest-and-zip-in-reactivecocoa/

/Users/fan/dev/cdap/cdap-ui/app/cdap/components/ConnectionExample/index.js

Angular有 IOC,react/node.js 没有这个机制?导致 angular 的代码很难在 React 中使用。

Test

$ cd /Users/fan/dev/cdap/cdap-ui/app/cdap/services 
$ npm test metadata-parser 

What’s new in React 16.3(.0-alpha) 正式引入了 Context API。有了它,实际上不需要Redux或其他全局状态管理库了。要使用 context,必须嵌入在一个 ThemeContext.Consumer 里面,这其实是另外一种形式的 Redux connect 了。这个是传入信息,怎么修改呢?mapStateToProps, mapDispatchToProps,第一个有了,怎么做第二个呢?当 context 改变的时候,组件肯定是自动更新了。

如何解读 react 16.3 引入的新 context api?这里说这种写法比 connect 直观了很多(确实),代码的整体可复用性也提升了许多(?)”Context 作为一个实验性质的 API,直到 React v16.3.0 版本前都一直不被官方所提倡去使用,其主要原因就是因为在子组件中使用 Context 会破坏 React 应用的分形架构。 这里的分形架构指的是从理想的 React 应用的根组件树中抽取的任意一部分都仍是一个可以直接运行的子组件树。在这个子组件树之上再包一层,就可以将它无缝地移植到任意一个其他的根组件树中。”

更多还是清晰明了吧。ThemeContext.Consumer 是组件,而 connect 是 JavaScript 代码。

http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

react-new-lifecycle

react-path

https://github.com/adam-golab/react-developer-roadmap

WebStorm推荐的Starter Kit(现在已经不推荐)

https://github.com/kriasoft/react-starter-kit/blob/master/docs/getting-started.md 这个 starter kit 摆脱了Ruby的依赖(我们项目中 ruby 提供compass),只需要 Node.js,所以环境的配置很简单。他用的是 postcss 来处理 scss,然后也没用 gulpfile,而是用的 webpack 集成 postcss。没有集成 Redux,作为一个 feature 提供。

似乎不大稳定,我提过一个问题:https://github.com/kriasoft/react-starter-kit/issues/772 modify routes/register/Register.js but UI didn’t reload

src/server.js create src/components/Html.js as a whole page. src/server.js import all routers. For home page, it will redirect to index.js by default? No index.js defined in server.js. server.js just include the ‘routes’ directory.

src/routes/index.js include src/components/App.js. And src/components/App.js has a template which include layout like Header & Footer.

Isomorphic : Isomorphic JavaScript apps are JavaScript applications that can run both client-side and server-side.

The backend and frontend share the same code. 这个在其首页被反复强调。优点么,seo、性能和维护。

各种 React Starter Kit

http://engineering.blogfoster.com/jumpstart-to-react-redux-development/

React for handling UI, Redux for managing state, Webpack as bundler, and ES2015 with Babel, as programming language. On the server side, Hapi.js for the REST API, MySQL and Sequilize as a data storage and access.

UI控件库用的是http://www.material-ui.com/#/ 这个是 React 组件库 更新很频繁,但是现在版本还是 0.x,有待稳定。

webpack编译后的合到一个文件webpack/dist/app.js,有5MB大。webpack/dev.config.js里面有调用babel。所以webpack基本上是一个类似gulp/grunt/ant的工具。

修改后页面并不是刷新/reload,而是页面上直接修改/部分更新,挺神奇的。

Create React App

现在官方推荐使用 https://github.com/facebookincubator/create-react-app, webstorm 里面带的也是这个。我试了下,是很简洁,但是 redux 也没有,有热替换,但是要刷新屏幕。

这个代码虽然简单,但是文档是一流的。

关于热替换,https://github.com/facebookincubator/create-react-app/issues/1063 这里讨论了很多。可以简单的加上 module.hot.accept, 这样就可以不刷新屏幕,但是只是快速的加载,component 的状态和值丢失了(比如组件里面的某个 input 的值),而且对于每个组件都要这样搞下。里面建议用 React Hot Loader。下面的 React Boilerplate 是怎么做到的呢?它好像用了不同的东西,找到这个 commit

React Boilerplate

http://www.reactboilerplate.com/

修改 app/components/Header/index.js 页面局部刷新

修改 app/containers/HomePage/index.js 全部刷新。这个整个页面的 layout,所以要刷新?

修改 app/containers/FeaturePage/index.js,局部刷新,奇怪

我提交了一个问题反应这个 https://github.com/react-boilerplate/react-boilerplate/issues/1573 原来 hot reload works for React.Component only. Not React.PureComponent or function.

这个 js 如果有语法错误也会在界面上显示蒙版,和 vue 一样。

使用 scaffolding 来创建一个 container(页面)直接运行 npm run generate,这是个交互式的命令行工具,可以生成很多东西(container, component, route, language)。container 和 component 其实都是 extends React.Component,这样区分有毛意义?

做一个交互式的例子:

1)输入框的双向绑定,和 angular.com 一样,一个输入框 + 一个文本显示

2)按钮触发动作,修改一个文本显示

思考:

  1. 一个 component 一边用着 ES6 Class,一边居然要定义 propTypes。不纯粹。很多地方留着些莫名其妙的孤立的代码。
  2. JSX 里面普通的<input>都被修改 css 了导致页面空白显示,为什么?强制用组件?
  3. component 的 CSS 都是 .jaFwra 这种 uuid,热部署发布,组件分离。生产模式下也是这样?如何集成 SCSS?