Redux ExampleのTodoListをReact Native(expo)に置き換えて解説のToggleTodo編です。
AddTodo編は以下です。
Redux ExampleのTodoListをReact Native(expo)に置き換えて解説AddTodo編
注:僕は掛け出しエンジニアであり、自分の勉強としての投稿という面もあるので、もしミスや勘違い、ベストプラクティスではない、等がありましたら、コメントしていただけると幸いです。
#TODOに属性を追加
まずは、todoにcomplete属性を追加してtodoが完了済みなのかactive状態なのかを判定できるようにします。初期値はfalseにしておきます。
const todoReducers = (state = [], action) => {
switch(action.type){
case 'ADD_TODO':
return [
...state,
{
id: action.id,
text: action.text,
completed: false //追加
}
]
default:
return state
}
}
export default todoReducers
Todoのcompleted属性がtrueかfalseによって見た目を変えたいので、TodoListコンポーネントを修正します。
class TodoList extends Component {
render() {
return (
<View>
<FlatList
data={this.props.todos}
renderItem={({ item }) => (
<View style={styles.todoList}>
<Text
style={{
textDecorationLine: item.completed ? "line-through" : "none",
}} //追加↑
>
{item.text}
</Text>
</View>
)}
keyExtractor={(item) => item.id.toString()}
/>
</View>
);
}
}
ここで、動作確認のため、reducers/todos.jsのcompleted属性をtrueにしてみましょう。todoに斜線が引かれていると思います。
#Actionからcompleted属性を操作する
次に、上記でやったtrue,falseの操作をActionを経由して操作できるようにしましょう。
まずはActionCreatorを作成します。どのtodoに横線を引くかを判別するためにidを取得します。
let nextTodoId = 0
export const addTodo = text => ({
type: 'ADD_TODO',
id: nextTodoId++,
text
})
//追加
export const toggleTodo = (id) => {
return {
type: "TOGGLE_TODO",
id,
};
};
reducersも変更します。
const todoReducers = (state = [], action) => {
switch (action.type) {
case "ADD_TODO":
return [
...state,
{
id: action.id,
text: action.text,
completed: true,
},
];
case "TOGGLE_TODO": //追加
return state.map((todo) =>
todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
);
default:
return state;
}
};
export default todoReducers;
やっていることとしては、stateに保存されている全てのtodoについて、それぞれのidとActionCreatorに渡された、横線を引きたいtodoのidを比べて、一致したらそのtodoのcompleted属性を逆転させるというものです。
ここで、例の如くApp.jsから動作確認をしてみましょう
App.jsに以下を追加してみましょう。
import { addTodo, toggleTodo } from './actions'
store.dispatch(addTodo('Hello React!'))
store.dispatch(toggleTodo(0))
画面をみてみると斜線が引かれたtodoが追加されているはずです。
#Todoをクリックしてcompleted属性を操作できるようにする
それでは、画面上からtodoの完了、未完了の操作ができるようにしましょう。mapDispatchToPropsを作成します。
これはcomponentで(今回で言えばTodoListで)dispatchをpropsとして渡せるものです。
こうすることで、component側ではthis.props.onTodoClick(id)の形で先ほどApp.jsでやったdispatch(toggleTodo(0))みたいなことができるようになります。
import { connect } from "react-redux";
import TodoList from "../components/TodoList";
import { toggleTodo } from "../actions"; //追加
const mapStateToProps = (state) => {
return { todos: state.todoReducers };
};
//追加
const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch(toggleTodo(id));
},
};
};
//追加
const VisibleTodoList = connect(mapStateToProps, mapDispatchToProps)(TodoList);
export default VisibleTodoList;
これでTodoListの方でonTodoClickが使えるようになったので、追加してみましょう。
return (
<View>
<FlatList
data={this.props.todos}
renderItem={({ item }) => (
<View style={styles.todoList}>
<Text
onPress={() => this.props.onTodoClick(item.id)}
style={{
textDecorationLine: item.completed ? "line-through" : "none",
}}
>
{item.text}
</Text>
</View>
)}
keyExtractor={(item) => item.id.toString()}
/>
</View>
);
これでtodoをクリックすると該当のtodoに斜線が引かれます。
ToggleTodo編は完成です!
お手元のシミュレーターでお試しください。
ここまでのソースコードはGitHubに上げていますのでご参考ください。
次回は表示するTodoをcompleted属性によって切り替える「FilterTodo」機能を実装していきます。