Redux ExampleのTodo ListをはじめからていねいにをTypescriptで(1),
Redux ExampleのTodo ListをはじめからていねいにをTypescriptで(2)の続き。
Redux ExampleのTodo Listをはじめからていねいに(3)をtypescriptで書いたメモ。
1. actionCreatorとreducerでフィルターの値をstore(state)に格納
actionCreatorの作成
src/actions/index.tsx
// 省略
export interface IVisibilityFilter extends Action{
type: 'SET_VISIBILITY_FILTER',
filter: string
}
//省略
export const setVisibilityFilter = (filter:string) : IVisibilityFilter => {
return {
type: 'SET_VISIBILITY_FILTER',
filter
}
}
reducersの作成
src/reducers/visibilityFilter.tsx
import { IVisibilityFilter } from '../actions';
const visibilityFilter = (state = 'SHOW_ALL', action:IVisibilityFilter) => {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter
default:
return state
}
}
export default visibilityFilter;
src/reducers/index.tsx
import { combineReducers } from 'redux'
import todos from './todos'
import visibilityFilter from './visibilityFilter';
const todoApp = combineReducers({
todos,
visibilityFilter
});
export default todoApp;
確認
src/app.tsx
// 省略
import { addTodo, toggleTodo, setVisibilityFilter } from './actions';
// 省略
console.log(store.getState()) // => Object {todos: Array[0], visibilityFilter: "SHOW_ALL"}
store.dispatch(setVisibilityFilter('SHOW_COMPLETED'))
console.log(store.getState()) // => Object {todos: Array[0], visibilityFilter: "SHOW_COMPLETED"}
// 省略
ここの時点のソース
2. フィルターの値によってviewを変更(手動でフィルターを操作して動作確認)
VisibleTodoListコンテナの修正
filterの値をストリングリテラル型で指定。
src/states/VisibilityFilterType.tsx
export type VisibilityFilterType = 'SHOW_ALL' | 'SHOW_COMPLETED' | 'SHOW_ACTIVE';
src/components/VisibleTodoList.tsx
// 省略
import { VisibilityFilterType } from '../states/VisibilityFilterType';
// 省略
const getVisibleTodos = (todos: TodoState[], filter:VisibilityFilterType):TodoState[] => {
switch (filter) {
case 'SHOW_ALL':
return todos
case 'SHOW_COMPLETED':
return todos.filter((t) => t.completed)
case 'SHOW_ACTIVE':
return todos.filter((t) => !t.completed)
}
}
const mapStateToProps = (store): IStateToProps => {
return {
todos: getVisibleTodos(store.todos, store.visibilityFilter)
}
}
ここの時点のソース
3. リンクをクリックしてフィルターを操作してviewを変更
とりあえず、リンクを表示させる
src/components/Link.tsx
import * as React from 'react';
import { Props, EventHandler, MouseEvent, Component } from 'react';
interface IProps extends Props<Link>{
children?: React.ReactElement<any>[];
}
interface IState {};
export default class Link extends Component<IProps, IState> {
render(): JSX.Element{
return (<a href="#">{this.props.children}</a>);
}
}
src/components/Footer.tsx
import * as React from 'react';
import { Props, EventHandler, MouseEvent, Component } from 'react';
import Link from './Link';
interface IProps {};
interface IState {};
export default class Footer extends Component<IProps, IState> {
render(): JSX.Element{
return (
<p>
Show:
{" "}
<Link>
All
</Link>
{", "}
<Link>
Active
</Link>
{", "}
<Link>
Completed
</Link>
</p>
);
}
}
src/components/App.tsx
import Footer from './Footer'
const App = () => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
)
ここの時点のソース
Linkコンテナでdispatch(setVisibilityFilter())を呼び出せるようにする
src/components/FilterLink.tsx
import { connect } from 'react-redux';
import { setVisibilityFilter } from '../actions';
import Link from '../components/Link';
import { VisibilityFilterType } from '../states/VisibilityFilterType';
interface IState{
visibilityFilter: VisibilityFilterType
}
interface IProps{
filter:VisibilityFilterType
}
interface IStateToProps{
state:any
}
interface IDispatchToProps{
onClick: Function
}
const mapStateToProps = (state:IState, ownProps:IProps):IStateToProps => {
return {
state:state
}
}
const mapDispatchToProps = (dispatch, ownProps:IProps):IDispatchToProps => {
return {
onClick: () => {
dispatch(setVisibilityFilter(ownProps.filter))
}
}
}
const FilterLink = connect(
mapStateToProps,
mapDispatchToProps
)(Link);
export default FilterLink
src/components/Footer.tsx
import * as React from 'react';
import { Props, EventHandler, MouseEvent, Component } from 'react';
import Link from './Link';
import FilterLink from '../containers/FilterLink'
interface IProps {};
interface IState {};
export default class Footer extends Component<IProps, IState> {
render(): JSX.Element{
return (
<p>
Show:
{" "}
<FilterLink filter="SHOW_ALL">
All
</FilterLink>
{", "}
<FilterLink filter="SHOW_ACTIVE">
Active
</FilterLink>
{", "}
<FilterLink filter="SHOW_COMPLETED">
Completed
</FilterLink>
</p>
);
}
}
クリックしたときにonClickを呼ぶ
src/components/Link.tsx
import * as React from 'react';
import { Props, Component } from 'react';
interface ILinkProps extends Props<Link>{
children?:any;
state:any;
onClick:Function;
}
interface ILinkState {};
class Link extends Component<ILinkProps, ILinkState> {
render(): JSX.Element{
return (
<a href="#"
onClick={(e) => {
e.preventDefault()
this.props.onClick()
}}
>{this.props.children}</a>
);
}
}
export default Link;
activeな状態なリンクを押せないようにする
src/components/FilterLink.tsx
// 省略
interface IStateToProps{
active: boolean
}
// 省略
const mapStateToProps = (state:IState, ownProps:IProps):IStateToProps => {
return {
active: ownProps.filter === state.visibilityFilter
}
}
// 省略
src/components/Link.tsx
import * as React from 'react';
import { Props, Component } from 'react';
interface ILinkProps extends Props<Link>{
children?:any;
active:boolean;
onClick:Function;
}
interface ILinkState {};
class Link extends Component<ILinkProps, ILinkState> {
render(): JSX.Element{
if (this.props.active) {
return <span>{this.props.children}</span>
}
return (
<a href="#"
onClick={(e) => {
e.preventDefault()
this.props.onClick()
}}
>{this.props.children}</a>
);
}
}
export default Link;
ここの時点のソース
参考
Redux ExampleのTodo Listをはじめからていねいに(3)
Redux ExampleのTodo ListをはじめからていねいにをTypescriptで(2)
Redux ExampleのTodo ListをはじめからていねいにをTypescriptで(1)
TypeScriptでのイベント名を管理・指定するもう一つの方法(+ストリングリテラル型にも対応)
TypeScript の JSX/React サポートを試す
TypeScript をざっとペロる