React 概念

组件

React 中的 UI 元素被称为组件。组件定义了 UI 元素的外观(布局、样式、动画)和行为。一旦定义了组件,就可以将其集成到其他组件中以构建完整的用户界面。

渲染

React 组件派生自模板基类 React.Component<P, S>。P 和 S 指的是 propsstate,这两个概念我们将在下面探讨。React 组件中最重要的方法是 render 方法。下面的示例展示了一个简单的 React 组件,它只渲染一些文本。

class HelloWorld extends React.Component<void, void> {
    render() {
        return <div>Hello World</div>;
    }
}

此示例使用 JSX 尖括号语法。TypeScript 1.6 包含对这种语法的原生支持。只需将源文件命名为“tsx”而不是“ts”文件扩展名。

请注意,此组件正在发出一个“div”标签,这仅在浏览器环境中有效。要将其转换为 ReactXP 组件,只需将“div”替换为“RX.Text”标签。

class HelloWorld extends RX.Component<void, void> {
    render() {
        return <RX.Text>Hello World</RX.Text>;
    }
}

另请注意,在上面的示例中,RX.Component 替换了 React.ComponentReactXP 重新导出 React.ComponentRX.Component,这样您的导入将保持整洁,您无需专门导入 React

属性

父组件通过指定参数来自定义子组件很方便。React 允许组件定义一组属性(或简称“props”)。一些 props 是必需的,另一些是可选的。props 可以是简单值、对象,甚至函数。

我们将修改 Hello World 示例以引入一个可选的“userName”prop。如果指定,组件将向用户渲染一个问候消息。组件类中的方法可以使用“this.props”访问 props。

interface HelloWorldProps {
    userName?: string; // Question mark indicates prop is optional
}

class HelloWorld extends RX.Component<HelloWorldProps, void> {
    render() {
        return (
            <RX.Text>
                { 'Hello ' + (this.props.userName || 'World') }
            </RX.Text>
        );
    }
}

样式

上面的示例使用默认样式(字体、大小、颜色等)渲染字符串。您可以通过指定“style”prop 来覆盖样式默认值。在此示例中,我们以绿色背景渲染粗体文本。请注意,React(和 ReactXP)中的样式大量借鉴了 CSS。

// By convention, styles are created statically and referenced
// through a private (not exported) _styles object.
const _styles = {
    container: RX.Styles.createViewStyle({
        backgroundColor: 'green'
    }),
    text: RX.Styles.createTextStyle({
        color: 'red',
        fontSize: 36, // Size in pixels
        fontWeight: 'bold'
    })
};

class HelloWorld extends RX.Component<void, void> {
    render() {
        return (
            <RX.View style={ _styles.container }>
                <RX.Text style={ _styles.text }>
                    Hello World
                </RX.Text>
            </RX.View>
        );
    }
}

有关样式属性的更多详细信息,请参阅样式文档或每个组件的文档。

布局指令

React 使用 flexbox 指令进行组件布局。这些指令与样式信息一起指定。网上有许多 flexbox 教程。此处是我们特别推荐的一个。使用 flexbox 指令,您可以指定主要布局方向(行或列)、对齐、对齐方式和间距。

React 还借鉴了 CSS 中的外边距和内边距概念。外边距是组件周围的空间量,内边距是组件边界与其子组件之间的空间量。

这是一个结合了外边距、内边距和 flexbox 指令的样式示例。

const _styles = {
    container: RX.Styles.createViewStyle({
        flexDirection: 'column',
        flexGrow: 1,
        flexShrink: 1,
        alignSelf: 'stretch',
        justifyContent: 'center',
        margin: 4,
        padding: 4,
        backgroundColor: 'green'
    })
};

有关布局指令的更多详细信息,请参阅样式文档。

事件处理

事件,例如用户手势、按键或鼠标操作,通过作为 props 指定的事件处理回调来报告。在此示例中,组件为按钮注册了一个 onPress 回调。

class CancelButton extends RX.Component<void, void> {
    render() {
        return (
            <RX.Button onPress={ this._onPress }>
                Cancel
            </RX.Button>
        );
    }

    private _onPress = (e: RX.SyntheticEvent) => {
        e.stopPropagation();

        // Cancelation logic goes here.
    }
}

此示例使用 TypeScript lambda 函数在类创建时将 _onPress 变量绑定到方法实例。它还演示了一些约定(使用变量名“e”表示事件对象,以及以 _ 开头的方法名表示它是私有的)。它还演示了一个最佳实践(调用 stopPropagation 方法表示事件已处理)。

状态

正如我们在上面的示例中看到的,组件的外观和行为可以根据外部提供的 props 发生变化。它还可以根据其内部管理的状态发生变化。作为一个简单的示例,当用户将鼠标悬停在组件上时,视觉样式可能会发生变化。

React 组件可以定义一个 state 对象。当此对象通过使用 setState 方法更新时,组件的 render 方法会自动调用。在下面的示例中,我们实现了一个简单的红绿灯,它有两种状态。根据当前状态,灯光被绘制成红色或绿色。按下或单击会切换状态。

interface StopLightState {
    // Fields within a state object are usually defined as optional
    // (hence the question mark below) because calls to setState
    // typically update only a subset of the fields.
    isStopped?: boolean;
}

const _styles = {
    redButton: RX.Styles.createViewStyle({
        width: 30,
        height: 30,
        borderRadius: 15,
        backgroundColor: 'red'
    }),
    greenButton: RX.Styles.createViewStyle({
        width: 30,
        height: 30,
        borderRadius: 15,
        backgroundColor: 'green'
    })
};

class StopLight extends RX.Component<void, StopLightState> {
    getInitialState(): StopLightState {
        return { isStopped: true };
    }

    render() {
        // Choose the appropriate style for the current state.
        var buttonStyle = this.state.isStopped ?
            _styles.redButton : _styles.greenButton;

        return (
            <RX.Button style={ buttonStyle }
                onPress={ this._onToggleState } />
        );
    }

    private _onToggleState = (e: RX.MouseEvent) => {
        e.stopPropagation();

        // Flip the value of "isStopped" and re-render.
        this.setState({ isStopped: !this.state.isStopped });
    }
}

组件状态也可以存储为类定义的实例变量。但是,如果 render 方法使用了数据片段,最好将其添加到 state 对象并通过调用 setState 进行更新。这样,渲染的组件将始终反映当前状态。