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');
复制代码
相关文章
相关标签/搜索