3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Redux ExampleのTodo ListをはじめからていねいにをTypescriptで(3)

Posted at

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"}

// 省略

ここの時点のソース

github

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)
  }
}

ここの時点のソース

github

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>
)

ここの時点のソース

github

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;

ここの時点のソース

github

参考

Redux ExampleのTodo Listをはじめからていねいに(3)
Redux ExampleのTodo ListをはじめからていねいにをTypescriptで(2)
Redux ExampleのTodo ListをはじめからていねいにをTypescriptで(1)
TypeScriptでのイベント名を管理・指定するもう一つの方法(+ストリングリテラル型にも対応)
TypeScript の JSX/React サポートを試す
TypeScript をざっとペロる

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?