我正在学习redux todomvc,并对下面的源代码有一些疑问。欢迎任何评论。感谢。
Q1:为什么没有调用store.dispatch()和store.subscribe()?看来这个例子与data flow introduction有点不同。
第二季度:任何人都能解释一下新项目会发生什么吗? src / index.js,src / containers / App.js,src / components / Header.js,src / components / TodoTextInput.js如何处理新的项目?问题3:来自(src / containers / App.js)的待办事项和行动在哪里?
问题4:这个状态=== store.getState()(在src / components / TodoTextInput.js中)?
// src/index.js
import React from 'react'
import { render } from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import App from './containers/App'
import reducer from './reducers'
import 'todomvc-app-css/index.css'
const store = createStore(reducer)
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
// src/containers/App.js
import React, { PropTypes } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import Header from '../components/Header'
import MainSection from '../components/MainSection'
import * as TodoActions from '../actions'
const App = ({todos, actions}) => (//Q3: where are todos and actions from?
<div>
<Header addTodo={actions.addTodo} />
<MainSection todos={todos} actions={actions} />
</div>
)
App.propTypes = {
todos: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired
}
const mapStateToProps = state => ({
todos: state.todos
})
const mapDispatchToProps = dispatch => ({
actions: bindActionCreators(TodoActions, dispatch)
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(App)
// src/components/Header.js
import React, { PropTypes, Component } from 'react'
import TodoTextInput from './TodoTextInput'
export default class Header extends Component {
static propTypes = {
addTodo: PropTypes.func.isRequired
}
handleSave = text => {
if (text.length !== 0) {
this.props.addTodo(text)
}
}
render() {
return (
<header className="header">
<h1>todos</h1>
<TodoTextInput newTodo// where is it from?
onSave={this.handleSave}
placeholder="What needs to be done?" />
</header>
)
}
}
// src/components/TodoTextInput.js
import React, { Component, PropTypes } from 'react'
import classnames from 'classnames'
export default class TodoTextInput extends Component {
static propTypes = {
onSave: PropTypes.func.isRequired,
text: PropTypes.string,
placeholder: PropTypes.string,
editing: PropTypes.bool,
newTodo: PropTypes.bool
}
state = {//Q4: this state === store.getState()?
text: this.props.text || ''
}
handleSubmit = e => {
const text = e.target.value.trim()
if (e.which === 13) {
this.props.onSave(text)
if (this.props.newTodo) {
this.setState({ text: '' })
}
}
}
handleChange = e => {
this.setState({ text: e.target.value })
}
handleBlur = e => {
if (!this.props.newTodo) {
this.props.onSave(e.target.value)
}
}
render() {
return (
<input className={
classnames({
edit: this.props.editing,
'new-todo': this.props.newTodo
})}
type="text"
placeholder={this.props.placeholder}
autoFocus="true"
value={this.state.text}
onBlur={this.handleBlur}
onChange={this.handleChange}
onKeyDown={this.handleSubmit} />
)
}
}
// src/components/TodoItem.js
import React, { Component, PropTypes } from 'react'
import classnames from 'classnames'
import TodoTextInput from './TodoTextInput'
export default class TodoItem extends Component {
static propTypes = {
todo: PropTypes.object.isRequired,
editTodo: PropTypes.func.isRequired,
deleteTodo: PropTypes.func.isRequired,
completeTodo: PropTypes.func.isRequired
}
state = {
editing: false
}
handleDoubleClick = () => {
this.setState({ editing: true })
}
handleSave = (id, text) => {
if (text.length === 0) {
this.props.deleteTodo(id)
} else {
this.props.editTodo(id, text)
}
this.setState({ editing: false })
}
render() {
const { todo, completeTodo, deleteTodo } = this.props
let element
if (this.state.editing) {
element = (
<TodoTextInput text={todo.text}
editing={this.state.editing}
onSave={(text) => this.handleSave(todo.id, text)} />
)
} else {
element = (
<div className="view">
<input className="toggle"
type="checkbox"
checked={todo.completed}
onChange={() => completeTodo(todo.id)} />
<label onDoubleClick={this.handleDoubleClick}>
{todo.text}
</label>
<button className="destroy"
onClick={() => deleteTodo(todo.id)} />
</div>
)
}
return (
<li className={classnames({
completed: todo.completed,
editing: this.state.editing
})}>
{element}
</li>
)
}
}
答案 0 :(得分:0)
Q1为什么没有调用store.dispatch()和store.subscribe()?
因为&#39;容器&#39;。在redux中,容器是订阅商店中的更改的组件。这是通过Redux的mapStateToProps
,mapDispatchToProps
完成的,最后是container file
connect
函数调用
connect
函数在内部调用store.subscribe
。
Q2:有人可以解释新项目会发生什么吗?
App
容器通过mapDispatchToProps
actions
道具传递给App
组件
此道具actions
包含addTodo
行动,已过去Header
Header
组件在addTodo
为saved
TextInput
操作
将调度addTodo
操作
reducer handles动作并用新项更新状态。商店已更新。
商店更新会触发App
容器重新呈现更新的道具,因为App
容器有mapStateToProps
完成
问题3:(src / containers / App.js)的待办事项和行动在哪里?
这也是因为Redux的connect
功能。它将从mapStateToProps
和mapDispatchToProps
获取返回值,合并它们并将其作为道具传递给App
组件。 todos
来自mapStateToProps
而actions
来自mapDispatchToProps
不要混淆。Q4这个状态=== store.getState()
state
中的TodoTextInput
是React的本机组件状态,与Redux的状态无关。但是,如果您的应用程序中需要一个状态,则需要确定它是应该存在于Redux存储中还是存在于组件本身中。
如果状态仅与组件本身相关,并且没有其他组件需要知道该状态的状态,则表明它应该存在于组件内部而不是在Redux的存储中。
TodoTextInput
组件中的状态在用户提交更改之前保留用户输入临时值。它非常适合作为组件本身的内部状态。