Things you need to know about React

1) It’s not a framework

2) JSX

const rootElement =
React.createElement(‘div’, {},
React.createElement(‘h1’, {style: {color: ‘red’}},
‘The world is yours’),
React.createElement(‘p’, {},
‘Say hello to my little friend’)
)
ReactDOM.render(rootElement, document.getElementById(‘app’))
const RootElement = (
<div>
<h1 style={{color: red}}>The world is yours</h1>
<p>Say hello to my little friend</p>
</div>
)
ReactDOM.render(RootElement, document.getElementById('app'))

3) It’s JavaScript

<select value={this.state.value} onChange={this.handleChange}>
{somearray.map(element => <option value={element.value}>
{element.text}
</option>)}
</select>
<select onChange={this.handleChange}>
{somearray.map(element => (
<option
value={element.value}
selected={this.state.value === element.value}
>
{element.text}
</option>
))}
</select>
<select
ng-model="selectedItem"
ng-options="item as item.name for item in items">
</select>

4) It’s declarative

<select value={this.state.value} onChange={this.handleChange}>
{somearray.map(element => <option value={element.value}>
{element.text}
</option>)}
</select>

5) You separate the concerns

6) Data goes down

<div>
<Greetings color={red} text='Hello' />
</div>
const Greetings = React.createClass({
render () {
const {color, text} = this.props
const divStyle = {padding: 10, backgroundColor: 'black'}
const headingStyle = {color: color}
return (
<div style={divStyle}>
<h1 style={headingStyle}>{text}</h1>
</div>
)
}
})

7) State

const InputBox = React.createClass({
getInitialState () {
return {
text: ''
}
},
changeText (event) {
this.setState({text: event.target.value})
},
render () {
return (
<div>
<input type='text' onChange={this.changeText}
placeholder='text' value={this.state.text} />
<span>{this.state.text}</span>
</div>
)
}
})
// BAD:
// ...
someFunction (value) {
this.setState({someValue: value})
// may not be changed at this point
console.log('New value: ', this.state.someValue)
}
// ...
// GOOD:
// ...
someFunction (value) {
this.setState({someValue: value}, () => {
// do stuff with new state
console.log('New value: ', this.state.someValue)
})
}
// ...

8) Events go up

const Parent = React.createClass({
gimmeThatState (textFromInput) {
console.log(textFromInput)
// or this.setState({text: textFromInput})
},
render () {
<InputBox pushChangesUp={this.gimmeThatState} />
}
})
const InputBox = React.createClass({
propTypes: {
pushChangesUp: React.PropTypes.func.isRequired
},
getInitialState () {
return {
text: ''
}
},
changeText (event) {
this.setState({text: event.target.value})
},
pushChangesUp () {
this.props.pushChangesUp(this.state.text)
}
render () {
return (
<div>
<input type='text' onChange={this.changeText}
placeholder='text' value={this.state.text} />
<span>{this.state.text}</span>
<button onClick={this.pushChangesUp}>
Push changes up
</button>
</div>
)
}
})

9) How rendering works

10) Composition is the key

11) Keep the state small

const initialState = [
{id: 1, text: 'laundry'},
{id: 2, text: 'shopping'}
// ...
]
const List = React.createClass({
getInitialState () {
return {
todos: initialState
}
},
render () {
return (
<div>
<ul>
{this.state.todos.map(todo => <li key={todo.id}>{todo.text}</li>)}
</ul>
</div>
)
}
})
const initialState = [
{id: 1, text: 'laundry'},
{id: 2, text: 'shopping'}
// ...
]
const List = React.createClass({
getInitialState () {
return {
todos: initialState,
filteredTodos: null
}
},
search (searchText) {
const filteredTodos = this.state.todos.filter(todo =>
todo.text.indexOf(searchText) > 0)
this.setState({filteredTodos: filteredTodos})
},
render () {
// get todos from state
const {filteredTodos, todos} = this.state
// if there are filtered todos use them
const list = filteredTodos === null ? todos : filteredTodos
return (
<div>
<SearchBox onChange={this.search} />
<ul>
{list.map(todo => <li key={todo.id}>{todo.text}</li>)}
</ul>
</div>
)
}
})
const initialState = [
{id: 1, text: 'laundry'},
{id: 2, text: 'shopping'}
// ...
]
const List = React.createClass({
getInitialState () {
return {
todos: initialState,
searchText: null
}
},
search (searchText) {
this.setState({searchText: searchText})
},
filter (todos) {
if (!this.state.searchText) {
return todos
}
return todos.filter(todo =>
todo.text.indexOf(this.state.searchText) > 0)
},
render () {
const {todos} = this.state
return (
<div>
<SearchBox onChange={this.search} />
<ul>
{this.filter(todos).map(todo => <li key={todo.id}>
{todo.text}
</li>)}
</ul>
</div>
)
}
})

12) Conditional rendering

Ternary operator

React.createClass({
getInitialState () {
return {
hideTodos: true
}
},
render () {
return (
<div>
{
hideTodos ? 'Sorry there is no data' : <TodoList />
}
</div>
)
}
})

Helper function

React.createClass({
getInitialState () {
return {
hideTodos: true
}
},
renderTodos () {
if (this.state.hideTodos) {
return 'Sorry there is no data'
}
return <TodoList />
}
render () {
return (
<div>
{
this.renderTodos()
}
</div>
)
}
})

A component

React.createClass({
getInitialState () {
return {
hideTodos: true
}
},
render () {
return (
<div>
<HideIf condition={this.state.hideTodos}>
<TodoList />
</HideIf>
</div>
)
}
})
const HideIf = React.createClass({
render () {
if (this.props.condition) {
return <span>'Sorry there is no data'</span>
}
// children is what's inside <HideIf> element
return this.props.children
}
})

13) You don’t need Flux

Wrap-up

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store