React applications are split into components which share information over different ways like state and properties.
Write first component
// MyComponent.js
import React from 'react'
class MyClass extends React.Component {
render (
return(
<div></div>
)
)
}
export default MyClass
Render it on the HTML
// index.js
import React from 'react'
import { render } from 'react-dom'
import MyComponent from './MyComponent'
render(<StorePicker />, document.getElementById('main'))
Can also be included with
import './style.css'
Processed by Webpack
add attributes to components
<Component myProp='data' myObj={JSObj} onClick={doSth}>
access variables via props
class MyComponent extends React.Component {
render(
return(
<p>{this.props.myProp}</p>
<p>{this.props.myObj}</p>
<p>{this.props.onClick}</p>
)
)
}
replace class MyClass ... with
const MyFunction = (props) => {
return(
<p>{props.myProp}<\/p>
<p>{props.myObj}<\/p>
<p>{props.onClick}<\/p>
)
}
Don't render component directly, but router
// index.js
import { BrowserRouter, Match, Miss } from 'react-router'
const Root = () => {
return (
<BrowserRouter>
<Match exactly pattern='/' component={MyComponent} \/>
<Match pattern='/mystuff/:myarg' component={MyStuff} \/>
<Miss component={OhNo} \/>
<\/BrowserRouter>
)
}
render(<Root />, document.getElementById('main'))
(Video 18): the ':myarg' will be available as this.props.params.myarg
Reference form elements as follows:
<input type='text' ref={(input)=>{ this.whateverName = input }}
now you can access it through 'this'.
You have to bind 'this' in functions other than render
See this example with event handling:
class MyClass extends React.Component {
constructor () {
super()
this.myFunction = this.myFunction.bind('this')
}
myFunction (event) {
this.nowAvailable('!!!')
event.preventDefault()
}
render () {
return (
<p onClick={this.myFunction.bind(this)}>test<\/p>
<p onClick={(e) => {this.myFunction(e)}}>test<\/p>
or
<p onClick={this.myFunction}>test<\/p> Needs constructor hack
)
}
}
Use context types:
// MyComponent.js
MyComponent.contextTypes = {
router: React.PropTypes.object
}
This gives access to these functions:
Usage:
this.context.router.transitionTo('...')
Initialize with
class App extends React.Component {
constructor () {
super()
this.state = {
child1state = {},
child2state = {},
}
}
render (
return (
...
)
)
}
When changing the state, you must avoid race conditions. Follow this scheme:
set the state with copy
class App extends React.Component {
constructor () {
super()
this.addChild1StateElement = this.addChild1StateElement.bind(this)
}
addChild1StateElement (elem) {
const child1state = { ...this.state.child1state }
child1state['new-item'] = elem
this.setState({ child1state })
}
render (
<ChildComponent addElem={this.addChild1StateElement} \/>
)
}
Create state manipulating functions on the main component and pass it to the children through props.
Example for
...
render () {
return (
<ul>
{Object.keys(this.state.child1state).map(key =>
<ChildComponent key={key} details={this.state.child1state[key]}\/>
)}
<\/ul>
)
}
...
each element in a loop needs a 'key' attribute, so React can keep track!
if you pass down 'key' itself, use a different name, e.g. index!
use data massaging to extract variables for easier access
const { details } = this.props
Object.keys(...).reduce((prevValue, key)=>{...}, initValue)
to make a scalar of an object.use componentWillUpdate(nextProps, nextState) in this case, because it is called every time state or props is updated.
...
componentWillMount () {
const localStorageRef = localStorage.getItem('mykey')
if (localStorage) {
this.setState({ order: JSON.parse(localStorageRef) })
}
}
componentWillUpdate () {
localStorage.setItem('mykey', JSON.stringify(nextState.mykey))
}
...
use shouldComponentUpdate() to check data before it is rendered. Returns true if component should be re-rendered or false if not.
You can used computed properties
...
handleChange (event, key) {
const prev = this.props.prevs[key]
const next = { ...prev, [event.target.name]: event.target.value }
this.setState(next)
}
render () {
return (
<input type='text' name='name' value={thing.name} placeholder='Thing name' onChange={(event) => this.handleChange(event, key)} \/>
)
}
...
javascript ... deleteElement (key) { const child1state = { ...this.statte.child1state } child1state[key] = null this.setState({ child1state }) } ...
* You can store JSX in a variable.
## Video 22: Animating React Components
* use npm package concurrently to concurrently start npm scripts
* use CSSTransitionGroup from 'react-addons-css-transition-group'
* adds and removes again classes to animated items
* class items can be styled with CSS
* replace parent element of animation
- e.g. <ul className='myclass'> becomes <CSSTransitionGroup className='myclass' component='ul' transitionName⁼'mytrans', transitionEnterTimeout={100} transitionLeaveTimeout={200}>
stylus
.mytrans background blue max-height 0px transition all 0.5s transform translateX(-120%) ... &.order-enter-active background yellow max-height auto transform translateX(0) ```