Model
Controller
View
Data
Stitching Logic
Template
MVC / MVVM / MV*
More information on my other slide
Title text field
let title = "";
Event
Watcher
Title text field
let title = "";
Watcher
Watcher
// Input JS
var component = <Viewer backgroundColor="#fff"/>
// Output JS
var component = React.createElement(Viewer, {backgroundColor: '#fff'});
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component {
render() {
return <div>Hello</div>
}
}
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component {
render() {
return <div>Hello</div>
}
}
ReactDOM.render(
<App/>,
document.getElementById("app")
);
class App extends React.Component {
render() {
return (<div>
<SearchBar/>
<Results/>
</div>);
}
}
/* Start SearchBar.js */
class SearchBar extends React.Component {
render() {
return <input/>
}
}
export default SearchBar;
/* End SearchBar.js */
/* Results.js */
class Results extends React.Component {
render() {
return <div>{heroes[0]}</div>
}
}
export default Results;
/* End Results.js */
Let's create some component first
import React from 'react';
import ReactDOM from 'react-dom';
import SearchBar from './Searchbar';
import Results from './Results';
class App extends React.Component {
render() {
return (<div>
<SearchBar/>
<Results/>
</div>);
}
}
Import now
From parent to child. Data flows down in react.
/* Child */
class Name extends React.Component {
render() {
return <div>{this.props.firstname} {this.props.lastname}</div>;
}
}
/* Parent */
class Parent extends React.Component {
render() {
return <div>
<Name firstname="Amanpreet" lastname="Singh"/>
</div>
}
|
From child to parent
/* Child */
class Name extends React.Component {
handleClick(e) {
this.props.onClickHandler(e, this.props.firstname + " " + this.props.lastname);
|
render() {
return <div onClick={this.handleClick}>{this.props.firstname} {this.props.lastname}</div>;
}
}
/* Parent */
class Parent extends React.Component {
onClickHandler(e, val) {
console.log(val)
}
render() {
return <div>
<Name
firstname="Amanpreet"
lastname="Singh"
onClickHandler={this.onClickHandler}/>
</div>
}
|
Similar to props, but private and controlled by component
Initialized in constructor, rerenders the component whenever the state changes
Props are fixed for lifetime, use state for data that is going to change
Remember the watcher we talked about in one way binding?
Adding state to parent
class App extends React.Component {
state = {
selectedHeroes: []
};
handleSearch(e) {
let searchValue = e.target.value;
if (searchValue.length === 0) {
this.setState({selectedHeroes: []})
return;
}
let filteredHeroes = heroes.filter((hero) => {
if (hero.indexOf(searchValue) > -1) {
return true;
} else {
return false;
}
});
this.setState({selectedHeroes: filteredHeroes});
}
render() {
return (<div>
<SearchBar handleSearch={this.handleSearch.bind(this)}/>
<Results selectedHeroes={this.state.selectedHeroes}/>
</div>);
}
}
SearchBar
class SearchBar extends React.Component {
handleChange(event) {
this.props.handleSearch(event);
}
render() {
return <input type="search" onChange={this.handleChange.bind(this)}/>
}
}
Pass state to Results
class Results extends React.Component {
render() {
let results = this.props.selectedHeroes.map((hero, index) => {
return <div key={index}>{hero}</div>;
});
return (
<div>{results}</div>
);
}
}
Better separation of concerns
const SearchBar = (props) => {
return <input type="search" onChange={(e) => {props.handleSearch(e)}}/>
}
const Results = (props) => {
let results = props.selectedHeroes.map((hero, index) => {
return <div key={index}>{hero}</div>;
});
return (
<div>{results}</div>
);
}
Predictable State Container for JavaScript Apps
As applications become complex, managing state becomes pain
Libraries like react remove asynchronicity and direct DOM manipulation but you still need to maintain state
State bloats with every increasing demands of a UI platform
The state of your whole application is stored in an object tree within a single store.
The only way to change the state is to emit an action, an object describing what happened.
To specify how the state tree is transformed by actions, you write pure reducers.
These reducers take in old state and an action and return back new state
(previousState, action) => newState
const { combineReducers, createStore, dispatch } = Redux;
const { connect, Provider } = ReactRedux;
Add imports
const selectedHeroesReducer = (state = [], action) => {
switch(action.type) {
case 'UPDATE_RESULTS': {
let searchValue = action.event.target.value;
if (searchValue.length === 0) {
return []
}
let filteredHeroes = heroes.filter((hero) => {
if (hero.indexOf(searchValue) > -1) {
return true;
} else {
return false;
}
});
return filteredHeroes
}
default: {
return state;
}
}
}
const reducers = combineReducers({
selectedHeroes: selectedHeroesReducer
});
const actions = {
updateResults: (e) => {
return {
type: 'UPDATE_RESULTS',
event: e
}
}
};
let store = createStore(reducers);
const SearchBar = (props) => {
return <input type="search" onChange={(e) => {props.handleSearch(e)}}/>
};
const mapDispatchToPropsForSearchBar = (dispatch) => {
return {
handleSearch: (e) => dispatch(actions.updateResults(e))
}
};
const VisibleSearchBar = connect(null, mapDispatchToPropsForSearchBar)(SearchBar);
const Results = (props) => {
let results = props.selectedHeroes.map((hero, index) => {
return <div key={index}>{hero}</div>;
});
return (
<div>{results}</div>
);
};
const mapStateToProps = (state) => {
return {
selectedHeroes: state.selectedHeroes
}
};
const VisibleResults = connect(mapStateToProps)(Results);
class App extends React.Component {
render() {
return (<div>
<VisibleSearchBar/>
<VisibleResults/>
</div>);
}
}
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById("app")
);