react简单原理
简单DEMO
var state = { value: null };
$('#input').on('keyup', function () {
state.value = $(this).val().trim();
render();
})
function render () {
$('#show').html(state.value);
}
render();
进一步 生成HTML节点
function div (text) {
return '<div>' + text + '</div>'
}
进一步 生成HTML节点
var state = {items: [], id: 0}
$('#add').on('click', function (e) {
var value = $('#input').val().trim()
$('#input').val('')
state.items.push({
id: state.id++,
text: value
})
render()
})
function render () {
var items = state.items.map(function (item) {
return '<li class="item"
id="' + item.id + '">(' +
item.id + ') ' + item.text + '</li>'
}).join('')
var html = '<ul>' + items = '</ul>'
$('#list').html(html)
}
render()
简化render
function ItemRow (props) {
var className = props.completed ? ' item completed' : 'item'
return '<li className="' + className +' ">' + props.text + '</li>'
}
function ItemsList (props) {
return '<ul>' + props.items.map(ItemRow).join('') + '</ul>'
}
function render () {
$('#list').html(ItemsList({
items: state.items
}))
}
减少全局变量的依赖
function render (props, node) {
node.html(ItemsList({
items: props.items
}))
}
能不能自动触发render?
function createStore (initialState) {
var _state = initialState || {},
_listeners = []
function updateListeners (state) {
_listeners.forEach(function (listener) {
listener.cb(state)
})
}
return {
setState: function (state) {
_state = state
updateListeners(state)
},
getState: function () {
return _state
},
onUpdate: function (name, cb) {
_listeners.push({name: name, cb: cb})
}
}
}
使用store
var store = createStore(state)
store.onUpdate('rootRender', function (state) {
render(state, $('#list'))
})
state.item.push({**********})
store.setState(state);
总结一下
1.单向数据流
2. 组件
3. state管理
<div id="app">
<input id="input" />
<button id="add">Add</button>
<div id="list"></div>
</div>
var state = { items: [], id: 0 };
$('#add').on('click', function(e) {
var value = $('#input').val().trim();
$('#input').val('');
state.items.push({id: state.id++, text: value, completed: false});
store.setState($.extend({}, state));
});
$('#list').on('click', '.item', function() {
var toggleId = parseInt($(this).attr('id'));
state.items.forEach(function(el) {
if (el.id === toggleId) {
el.completed = !el.completed;
}
});
store.setState($.extend({}, state));
});
function ItemRow(props) {
var className = props.completed? ' completed' : '';
return '<li class="item'+ className +'" id="' + props.id + '">(' +
props.id + ') '+ props.text + '</li>';
}
function ItemsList(props) {
return '<ul>' + props.items.map(ItemRow).join('') + '</ul>';
}
function render(props, node) {
node.html(ItemsList({items : props.items}));
}
function createStore(initialState) {
var _state = initialState || {}, _listeners = [];
function updateListeners(state) {
_listeners.forEach(function(listener) {
listener.cb(state);
});
}
return {
setState: function(state) {
_state = state;
updateListeners(state);
},
getState: function() {
return _state;
},
onUpdate: function(name, cb) {
_listeners.push({name: name, cb: cb});
}
};
}
var store = createStore(state);
store.onUpdate('rootRender', function(state) {
render(state, $('#list'));
});
组件绑定事件
function ItemRow (props) {
return $('<li>')
.on('click', props.onUpdate.bind(null, props.id))
.addClass('item')
.attr('id', props.id)
.html(props.text)
}
创建元素独立出来
function createElement (tag, attrs, children) {
var ele = $('<' + tag + '>')
for (var key in attrs) {
var val = attrs[key]
if (key.indexOf('on') === 0) {
var event = key.substr(2).toLowerCase()
ele.on(event, val)
} else {
ele.attr(key, val)
}
}
return ele.html(children)
}
function ItemRow (props) {
var className = props.completed ? 'item completed' : 'item'
return createElement('li', {
id: props.id,
class: props.className,
onClick: props.onUpdate.bind(null, props.id)
}, props.text)
}
react中新建元素
return (
<div id='el' className='entry'>
Hello
</div>
)
var SomeElement = React.createElement('div', {
id: 'el',
className: 'entry'
}, 'Hello')
{
// ...
type: 'div',
key: null,
ref: null,
props: {
children: 'Hello',
className: 'entry',
id: 'el'
}
}
onUpdate是哪来的呢?
function render (props, node) {
function updateState (toggleId) {
state.items.forEach(function (el) {
if (el.id === toggleId) {
el.completed = !el.completed
}
})
store.setState(state)
}
node.empty().append([ItemList({
items: props.items,
onUpdate: updateState
})])
}
onUpdate的传递
function extending (base, item) {
return $.extend({}, item, base)
}
function ItemsList (props) {
return createElement('ul', {}, props.items
.map(extending.bind(null, {
onUpdate: props.onUpdate
}))
.map(ItemRow))
}
再次简化
<div id="app">
<input id="input" />
<button id="add">Add</button>
<div id="list"></div>
</div>
<div id="app"></div>
再次简化
function SearchBar(props) {
function onButtonClick (e) {
var val = $('#input').val()
$('#input').val('')
props.update(val)
e.preventDefault()
}
var input = createElement('input', {id: 'input'})
var button = createElement('button', {
id: 'add',
onClick: onButtonClick.bind(null)
}, 'Add')
return createElement('div', {}, {input, button})
}
进一步整合searchbar和ItemList以及状态管理
function render (component, node) {
node.empty().append(component)
}
render(App(state), $('#app'))
进一步整合searchbar和ItemList以及状态管理
function App (props) {
function updateSearchBar (value) {
state.items.push({
id: state.id++,
text: value,
completed: false
})
store.setState(state);
}
function updateState (toggleId) {
state.items.forEach(function (el) {
if (el.id === toggleId) {
el.completed = !el.completed
}
})
store.setState(state)
}
return [
SearchBar({update: updateSearchBar}),
ItemsList({items: props.items, onUpdate: updateState})
]
}
自行管理state
function App (props) {
function getInitialState (props) {
return {
items: [],
id: 0
}
}
var _state = getInitialState(),
_node = null
function setState (state) {
_state = state
render()
}
function render(){}
// ..
}
render实现
function render () {
var children = [
SearchBar({update: updateSearchState}),
ItemList({
items: _state.items,
onUpdate: updateState
})
]
if (!_node) {
return _node = createElement('div', {class: 'top'}, children)
} else {
return _node.html(children)
}
}
大功告成
function render(component, node) {
node.empty().append(component)
}
render(App(), $('#app'))
<div id="app"></div>
function createElement(tag, attrs, children) {
var elem = $('<' + tag + '>');
for (var key in attrs) {
var val = attrs[key];
if (key.indexOf('on') === 0) {
var event = key.substr(2).toLowerCase();
elem.on(event, val)
} else {
elem.attr(key, val);
}
}
return elem.html(children);
}
function ItemRow(props) {
var className = props.completed ? ' item completed' : 'item';
return createElement('li', {
id: props.id,
class: className,
onClick: props.onUpdate.bind(null, props.id)
}, props.text);
}
function extending(base, item) {
return $.extend({}, item, base);
}
function ItemsList(props) {
return createElement('ul', {}, props.items.map(extending.bind(null, {
onUpdate: props.onUpdate
})).map(ItemRow));
}
function SearchBar(props) {
function onButtonClick(e) {
var val = $('#input').val();
props.update(val);
$('#input').val('');
e.preventDefault();
}
var input = createElement('input', {
id: 'input'
});
var button = createElement('button', {
id: 'add',
onClick: onButtonClick.bind(null)
}, 'Add');
return createElement('div', {
class: 'serach-bar'
}, [input, button]);
}
function App(props) {
function getInitialState(props) {
return {
items: [],
id: 0
}
}
var _state = getInitialState(),
_node = null;
function setState(state) {
_state = state;
render();
}
function updateSearchState(value) {
_state.items.push({
id: _state.id++,
text: value,
completed: false
});
setState(_state);
}
function updateState(toggleId) {
_state.items.forEach(function(el) {
if (el.id === toggleId) {
el.completed = !el.completed;
}
});
setState(_state);
}
function render() {
var children = [SearchBar({
update: updateSearchState
}), ItemsList({
items: _state.items,
onUpdate: updateState
})];
if (!_node) {
return _node = createElement('div', { class: 'main' }, children);
} else {
return _node.html(children);
}
}
return render();
}
function render(component, node) {
node.empty().append(component);
}
render(App(), $('#app'));
再次总结一下
1.单向数据流与事件流
2. 组件状态管理
2016-8月-分享
By Joson Chen
2016-8月-分享
- 352