diff: (Tree, Tree) → ∆Tree
render() { return <div>Hello World, at {new Date().toString()}</div>; }
⟱ JSX Transformer ⟱
render() { return React.createElement('div', {}, 'Hello World, at ', new Date().toString()); }
class App extends React.Component { render() { return ( <div className="main"> <div className="picture-bg"> <img src={getRandomBg()} /> </div> <Clock /> <CmdLine ps1="λ" /> <LinksBox /> </div> ); } }
class Clock extends React.Component { render() { let time = moment().format(this.props.format); return (<time>{time}</time>); } }
// ... render() { return (<div><Clock format="HH:mm" /></div>); } // ...
export let LookMaNoState = (props) => { return (<span>{props.name}</span>); } React.renderDom(<LookMaNoState name="Mark">, mountNode);
class ProductInfiniteScroller extends React.Component { scrollHander() {...} dataLoader() {...} reposition() {...} removeClippedSubviews() {...} render() { return ( <ul> {this.state.item.map((i) => { return (<span>{i.name}</span>); })} </ul> ); } }
<ScrollView horizontal={true|false} bounce={true|false} paging={true|false}> </ScrollView>
<ProductPrice data={data} /> <ProductPrice listPrice={data.price.list} markdownPrice={data.price.markdown} />
class MyComponent extends React.Component { onClickHandler() { this.props.user.likes += 1; } render() { // ... } }
class MyComponent extends React.Component { onClickHandler() { this.props.onLike(user.props.likes + 1); } render() { // ... } }
import {Record} from 'immutablejs'; let FooBar = Record({foo: 'baz', bar: 'blub'}); // ... let fb = new FooBar({foo: 'lorem'}); fb.get('foo') // -> 'lorem' let changed = fb.set('foo', 'bar'); fb.get('foo') === changed.get('foo') // -> false
class MyComponent extends React.Component { constructor(props) { super(props); this.state = { data: props.data } } }
Use the prop directly if you need to!
class MyComponent extends React.Component { componentWillReceiveProps(nextProps) { this.setState({ data: nextProps.data }); } }
You cannot call setState in componentWillUpdate!
MyComponent.propTypes = { someString: React.PropTypes.string, someEnum: React.PropTypes.oneOf(['A', 'B']), someArrayOf: React.PropTypes.arrayOf(React.PropTypes.number) }
<Slider images={[....]} />
<Slider> <Image /> <Image /> <Image /> </Slider>
Bad:
class RxButton extends React.Component { render() { return ( <TouchableHightlight> {this.props.children} </TouchableHightlight> ); } } <RxButton accessibilityLabel="button"> // ... </RxButton>
Good:
class RxButton extends React.Component { render() { return ( <TouchableHightlight accessibilityLabel={this.props.accessibilityLabel}> {this.props.children} </TouchableHightlight> ); } } <RxButton accessibilityLabel="button"> // ... </RxButton>
class RxButton extends React.Component { render() { return ( <RxButton {...this.props}> <RxIcon src="..." /> </RxButton> ); } } <RxIconButton accessibilityLabel="button"> // ... </RxIconButton>
“Using context makes your components more coupled and less reusable”
class MyWrapper extends React.Component { getChildContext() { return { mainColor: '#bada55' }; } }
class MyButton extends React.Component { render() { return ( <button style={{backgroundColor: this.context.mainColor}}> {this.props.children} </button> ); } }
console.log(this.context); // => {}
class MyWrapper extends React.Component { getChildContext() { return { mainColor: '#bada55' }; } } MyWrapper.childContextTypes = { mainColor: React.PropTypes.string };
class MyButton extends React.Component { render() { return ( <button style={{backgroundColor: this.context.color}}> {this.props.children} </button> ); } } MyButton.contextTypes = { mainColor: React.PropTypes.string };
class MyWrapper extends React.Component { getChildContext() { return this.state; } constructor(props) { super(props); UserSerivce.getUserByRoute(this.context.currentRoute) .then((user) => { this.setState({user}); }); } render() { return (<Profile />); } }assume contextTypes are set correctly
class Profile extends React.Component { // ... addAsFriend() render() { return ( <div className="user-profile"> <h3>{this.context.user.name}</h3> <span> {`Friends: ${this.context.user.friendCount}`} </span> <button onClick={this.addAsFriend.bind(this)}> Add As Friend </button> </div> ); } }
class Profile extends React.Component { addAsFriend() { this.context.user .addUser(this.context.currentUser); } // ... render() }
class MyWrapper extends React.Component { constructor(props) { super(props); } // data retrieval with Flux render() { return (<Profile user={this.state.user} />); } }
class Profile extends React.Component { // ... addAsFriend() render() { return ( <div className="user-profile"> <h3>{this.props.user.name}</h3> <span> {`Friends: ${this.props.user.friendCount}`} </span> <button onClick={this.addAsFriend.bind(this)}> Add As Friend </button> </div> ); } }
<input ref="username" type="text" value={this.props.username} /> // ... console.log(this.refs.username) // => HTMLElement
<MaterialTextInput ref="textinput" value={this.props.value} /> // ... console.log(this.refs.textinput) // => MaterialTextInput console.log(ReactDOM.findDOMNode(this.refs.textinput)) // => HTMLElement
class RefTest extends React.Component { render() { return ( <input ref={(i) => { this.input = i; }} type="text" value={this.props.username} /> ); } }
The componentDidMount() method of child components is invoked before that of parent components
import ReactTestUtils from 'react-addons-test-utils'
import {isElementOfType, isElement} from 'react-addons-test-utils'; test('existence', () => { expect(isElement(<MyComponent />)).to.be.true; expect(isElementOfType(<MyComponent />, MyComponent)).to.be.true; });Source
let shallowRenderer; setup(() => { shallowRenderer = createRenderer(); }); test('ensure correct sub components', () => { shallowRenderer.render(<MyComponent />) let output = shallowRenderer.getRenderOutput(); expect( isElementOfType(output.props.children, MySubComponent) ).to.be.true; });Source
var jsdom = require('jsdom'); var document = jsdom.jsdom('<!doctype html><html><body></body></html>'); var window = document.defaultView; global.document = document; global.window = window; for (var key in window) { if (!window.hasOwnProperty(key)) { continue; } else if (key in global) { continue; } else { global[key] = window[key] } }
renderIntoDocument(componentInstance)
import {Simulate} from 'react-addons-test-utils'; let node = renderIntoDocument(<MyComponent />);
function renderIntoDocument(instance) { var div = document.createElement('div'); return ReactDOM.render(instance, div); }
Nothing is actually rendered into the document.
This is great for test isolation!
findRenderedDOMComponentWithTag(node, tagName)
import {findRenderedDOMComponentWithTag} from 'react-addons-test-utils'; findRenderedDOMComponentWithTag(node, 'button'); // returns DOM node or throws error
findRenderedDOMComponentWithTag(node, tagName)
import {findRenderedComponentWithType} from 'react-addons-test-utils'; findRenderedComponentWithType(node, MySubComponent); // returns instance node or throws error // only works with fully 'rendered' nodes (not shallowly rendered)
import {Simulate} from 'react-addons-test-utils'; Simulate.click(clickableNode); // clickableNode is 'real' DOM node that has a onClick event, // i. e. <button>
Simulate.change(inputNode); Simulate.keyDown(inputNode, {key: 'Enter', keyCode: 13}); // Simulate.{eventName}(node, eventData); // for every event that React supports
clickHandler() { this.setState({hide: true}); } render() { if (this.state.hide) { return (<div></div>); } else { return ( <div> <MySubComponent name="testing" onClick={this.clickHandler.bind(this)} /> </div> ); } }
test('simulate click', () => { let node = renderIntoDocument(<MyComponent />); Simulate.click(findRenderedDOMComponentWithTag(node, 'button')); expect(findRenderedDOMComponentWithTag(node, 'div')).to.be.defined; expect( findRenderedDOMComponentWithTag .bind(undefined, node, 'button') ).to.throw(Error); });Source
test('simulate click', () => { let node = renderIntoDocument(<MyComponent />); Simulate.click(findRenderedDOMComponentWithTag(node, 'button')); expect(findRenderedDOMComponentWithTag(node, 'div')).to.be.defined; expect( findRenderedDOMComponentWithTag .bind(undefined, node, 'button') ).to.throw(Error); });Source
What does accessible={true} mean?
<View> <Slider> <Image resizeMode='contain' source={{uri: images[0]}} /> <Image resizeMode='contain' source={{uri: images[1]}} /> <Image resizeMode='contain' source={{uri: images[2]}} /> </Slider> </View>
<ScrollView accessibilityLabel="slider" horizontal={true} ...> {elements} </ScrollView>
let slider = XCUIApplication().otherElements["slider"] slider.swipeLeft() slider.swipeRight() slider.swipeLeft() slider.swipeLeft() XCTAssert(slider.images["image 3"].frame == slider.frame)
Requires 2 parts:
All Exceptions should be thrown in JS
import {expect} from 'chai'; import React from 'react-native'; let {AppRegistry, View, Component} = React; import {TestModule} from 'NativeModules'; class TestComp extends Component { render() { TestModule.markTestCompleted(); return (<View></View>); } } AppRegistry .registerComponent('ExampleTests', () => { return TestComp });
@implementation ExampleTests { RCTTestRunner *_runner; } - (void)setUp { [super setUp]; _runner = RCTInitRunnerForApp(@"intTestDist/tests.int", nil); } - void()testExampleTests { [_runner runTest:_cmd module:@"ExampleTests"] } @end