redux-actions學習

遵循FSA(Flux Standard Action)規則

簡單看了下,這個規則要點是:redux

action結構

  • type
  • payload(有效數據 或者 在error爲true時候爲一個錯誤對象)
  • error(錯誤標識)
  • meta(非有效數據的其餘數據)

type是必須的,其餘三個可選。規定action不能再有其餘屬性了。bash

錯誤處理

不要經過相似GET_DATA_SUCCESSGET_DATA_FAIL這樣的type去處理錯誤。而是經過設置error:true處理app

{
  type: 'GET_DATA',
  payload: new Error(),
  error: true
}
複製代碼

本質是actionCreater,並非action

redux-actions是建立各類actionCreater,action只是簡寫。調用生成的actionCreater函數纔會產生真正的action。函數

例如oop

const a = createAction('INCREMENT');
console.log(a(111))
複製代碼

產生的結果是ui

{
    type: 'INCREMENT',
    payload: 111
}
複製代碼

最簡單的流程

1. 建立一個actionCreater

const actionCreater = createAction('INCREMENT');
複製代碼

2. 經過actionCreater建立reducer

const reducer = handleAction(
  actionCreator,
  (state, action) => ({
    ...state,
    counter: state.counter + 1,
  }),
  { counter: 1 }
);
複製代碼

3. 調用dispatch

dispatch(actionCreater())
複製代碼

經過以上三步,能夠看出端倪了,可是並沒什麼用,咱們用redux的痛點是什麼?一堆switch,dispatch時候type亂飛等。下面讓咱們用redux-actions來實現經典官方例子todo。spa

實現一個簡單的todo

actionscode

export const add = createAction('ADD_TODO');
export const del = createAction('DELETE_TODO');
export const toggle = createAction('TOGGLE_TODO');
複製代碼

reducers對象

const defaultState = [];
const reducer = handleActions({
  [add]: (state, {payload}) => {
    return [...state, {
      text: payload,
      done: false
    }];
  },
  [del]: (state, {payload}) => {
    const ind = state.findIndex(item => item.text === payload);
    return [...state.slice(0, ind), ...state.slice(ind + 1)];
  },
  [toggle]: (state, {payload}) => {
    const ind = state.findIndex(item => item.text === payload);
    const todo = state[ind];
    console.log(ind, todo)
    return [
      ...state.slice(0, ind),
      {
        ...todo,
        done: !todo.done
      },
      ...state.slice(ind + 1)
    ]
  }
}, defaultState)
複製代碼

組件rem

function App() {
  const [todo, setTodo] = useState('');
  const dispatch = useDispatch();
  const state = useSelector(state => state);
  console.log('app');

  function handleChange(e) {
    setTodo(e.target.value);
  }
  function handleAdd() {
    dispatch(add(todo));
    setTodo('');
  }

  return (
    <div className="App">
      <input value={todo} onChange={handleChange} />
      <button onClick={handleAdd}>Add</button>
      <br />
      <ul>
        {state.map(({ text, done }) => (
          <li key={text}>
            <span
              onClick={() => dispatch(toggle(text))}
              style={done ? { textDecoration: 'line-through' } : null}
            >
              {text}
            </span>
            <button onClick={() => dispatch(del(text))}>X</button>
          </li>
        ))}
      </ul>
    </div>
  );
}
複製代碼
  • reducer中不用寫囉嗦的switch了
  • 組件中也能夠引入actionCreator生成action了

優點

1.reducer中無需寫囉嗦的switch了

2.定義action(實際上是actionCreator),多處引用,避免混亂

定義action

const increment = createAction('INCREMENT') 
複製代碼

在reducer中引用

const reducer = handleActionsWithImmer({
  [increment]: (state) => {
    return state + 1;
  },
  ...
複製代碼

在組件中引用

dispatch(increment());
複製代碼

3.自動處理異常

const noop = createAction('NOOP');
const error = new TypeError('not a number');
noop(error);
複製代碼

將自動生成一個error爲true的action

{
  type: 'NOOP',
  payload: error,
  error: true
}
複製代碼

在reducer中,能夠自行判斷error爲true做處理,也能夠以下聲明式處理。這樣,正常action會走next處理,若是error爲true的action會走throw處理

handleAction(noop, {
  next(state, action) {
    return action.payload;
  },
  throw(state, action) {
    console.log('出錯了', state, action);
    return state;
  }
}, 'xxxxx');
複製代碼
相關文章
相關標籤/搜索