functiontodos(state = [], action) {switch (action.type) {case'ADD_TODO':// Wrong! This mutates statestate.push({ text:action.text, completed:false })return statecase'COMPLETE_TODO':// Wrong! This mutates state[action.index]. state[action.index].completed =truereturn statedefault:return state }}
이렇게 고쳐야 합니다:
코드는 더 많지만 이게 바로 Redux를 예측 가능하고 능률적으로 만들어줍니다. 코드를 더 줄이고 싶다면 React.addons.update과 같은 헬퍼를 써서 간단한 문법으로 불변형 변환을 작성할 수 있습니다:
마지막으로, 객체를 업데이트하기 위해 Underscore의 _.extend 같은 것들이나, 더 좋은 Object.assign 폴리필 등을 사용할 수 있습니다.
Object.assign을 올바르게 사용하도록 하세요. 예를 들어 리듀서에서 Object.assign(state, newData) 처럼 반환하는 대신 Object.assign({}, state, newData)처럼 반환해야 합니다. 이렇게 하면 이전의 state를 덮어쓰지 않게 됩니다.
액션 생산자를 정의했다면, 이걸 호출한다고 자동으로 액션이 디스패치되지 않습니다. 예를 들어 이 코드는 아무것도 하지 않습니다:
TodoActions.js
AddTodo.js
액션 생산자는 단지 액션을 반환하는 함수일 뿐이기 때문에 이 코드는 작동하지 않습니다. 실제로 디스패치하는 것은 당신에게 달렸습니다. 서버에서 랜더링되는 앱의 경우 매 요청마다 별개의 스토어를 요구하기 때문에 액션 생산자를 정의하는 동안 특정 스토어 인스턴스에 바인드 할 수는 없습니다.
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
// Return a new array
return [
...state,
{
text: action.text,
completed: false
}
]
case 'COMPLETE_TODO':
// Return a new array
return state.map((todo, index) => {
if (index === action.index) {
// Copy the object before mutating
return Object.assign({}, todo, {
completed: true
})
}
return todo
})
default:
return state
}
}
// Before:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: true
})
}
return todo
})
// After
return update(state, {
completed: {
$set: true
}
}
})
// Before:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: true
})
}
return todo
})
// After:
return state.map((todo, index) => {
if (index === action.index) {
return { ...todo, completed: true }
}
return todo
})
export function addTodo(text) {
return { type: 'ADD_TODO', text }
}
import React, { Component } from 'react'
import { addTodo } from './TodoActions'
class AddTodo extends Component {
handleClick() {
// Won't work!
addTodo('Fix the issue')
}
render() {
return (
<button onClick={() => this.handleClick()}>
Add
</button>
)
}
}
handleClick() {
// Works! (but you need to grab store somehow)
store.dispatch(addTodo('Fix the issue'))
}
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { addTodo } from './TodoActions'
class AddTodo extends Component {
handleClick() {
// Works!
this.props.dispatch(addTodo('Fix the issue'))
}
render() {
return (
<button onClick={() => this.handleClick()}>
Add
</button>
)
}
}
// In addition to the state, `connect` puts `dispatch` in our props.
export default connect()(AddTodo)