debbygigigi / notes

My notes for any technologies of Web, Tech, etc.
9 stars 1 forks source link

[學習筆記] Redux #20

Open debbygigigi opened 5 years ago

debbygigigi commented 5 years ago

延續上一篇 react-app,直接改寫成加入 redux 的版本

安裝所需套件

npm install --save redux react-redux redux-thunk

連結 React 和 Redux

要讓 React 和 Redux 連結有兩種方式 第一種是 connect() 第二種是 provider

Provider 把整個 App 包起來

App.js

import { Provider } from 'react-redux'
...
<Router basename={process.env.PUBLIC_URL}>
        <Provider store={store}>
          <div className="App">
            <Header />
            <Route exact path="/" render={props => (
              <React.Fragment>
                <AddTodo addTodo={this.addTodo}/>
                <TodoList todos={this.state.todos} markComplete={this.markComplete}
                  deleteTodo={this.deleteTodo} />
              </React.Fragment>
            )} />
            <Route path="/about" component={About} />
          </div>
        </Provider>
      </Router>

reducer

建立 reducers/index.js

這邊 combind 所有 reducers

import { combineReducers } from 'redux';
import todoReducer from './todoReducer';

export default combineReducers({
  addTodo: todoReducer
})

reducers/todoReducer.js

import { FETCH_TODOS, ADD_TODO } from '../actions/types';

const initialState = {
  todos: []
}

// state, action
export default function(state = initialState, action) {
  switch (action.type) {
    default:
      return state
  }
}

action

action/type.js

export const FETCH_TODOS = 'FETCH_TODOS';
export const ADD_TODOS = 'ADD_TODOS';

action/todoAction.js

import { FETCH_TODOS, ADD_TODO } from '../actions/types';

export function fetchTodos () {
  return function(dispatch) {
    Axios.get('https://jsonplaceholder.typicode.com/todos?_limit=10')
    .then(todos => dispatch({
      type: FETCH_TODOS,
      payload: todos.data
    }))
  }
}

改成 arrow function

export const fetchTodos = () => dispatch => {
    Axios.get('https://jsonplaceholder.typicode.com/todos?_limit=10')
      .then(todos => dispatch({
        type: FETCH_TODOS,
        payload: todos.data
      }))
}

回到 reducer,新增一個 case

action/todoActions.js

export default function(state = initialState, action) {
  switch (action.type) {
    case FETCH_TODOS: {
      return {
        ...state,
        todos: action.payload
      }
    }
    default:
      return state
  }
}

跟 component 結合 用到 connect()

components/todoList.js

import { connect } from 'react-redux';
import { fetchTodos } from '../actions/todoActions';

componentWillMount() {
        this.props.fetchTodos();
    }

...
export default connect(null, {fetchTodos})(TodoList);

componentWillMount 這個階段呼叫 fetchTodos 注意的是,這裡的方式是用 props 取得

但是 store 裡的 state 如果要和 component 結合 就要使用 mapState

const mapStateToProps = state => {
    return {
        todos: state.todos.todos
    }
}
...
export default connect(mapStateToProps, {fetchTodos})(TodoList);

補上 props type

TodoList.propTypes = {
    fetchTodos: PropTypes.func.isRequired,
    todos: PropTypes.Array.isRequired
}

add redux devtool

Redux devtool https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd

安裝後會發現 redux 只出現 No store found. Make sure to follow the instructions.

這時要稍微修改一下 store.js

import { createStore, applyMiddleware, compose } from 'redux'
...
const store = createStore(
  rootReducer,
  initialState,
  compose(
    applyMiddleware(...middleware),
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
  ));

增加了 compose

SOP

  1. add new action type

先新增一個 type

export const ADD_TODO = 'ADD_TODO';
  1. add new action

todoAction.js

export const addTodo = (title) => dispatch => {
  Axios.post('https://jsonplaceholder.typicode.com/todos', {
      title,
      completed: false
    })
    .then(todos => dispatch({
      type: ADD_TODO,
      payload: todos.data
    }))
}
  1. add reducer
case ADD_TODO: {
      return {
        todos: [
          ...state.todos,
          action.payload
        ]
      }
    }
  1. connect

在要執行 function 的檔案

import { connect } from 'react-redux';
import { addTodo } from '../actions/todoActions';
...
onSubmit = (e) => {
    e.preventDefault();
    this.props.addTodo(this.state.title);
  }
...
export default connect(null, { addTodo })(AddTodo);
  1. add props-type
// propsType
AddTodo.propTypes = {
  addTodo: PropTypes.func.isRequired
}

reference

debbygigigi commented 5 years ago

reference:

https://ithelp.ithome.com.tw/articles/10186447 https://medium.com/@smile2gether/react-redux-todo-list-ccf63b622339 https://medium.com/frochu/%E9%80%81%E8%AE%93%E4%BD%A0%E7%9A%84action%E8%83%BD%E4%BD%9C%E6%9B%B4%E5%A4%9A-redux-thunk-c07bc5488e48

https://www.youtube.com/watch?v=1w-oQ-i1XB8 https://www.youtube.com/watch?v=AslncyG8whg