繁体   English   中英

使用 react/redux 共享操作和 reducer

[英]Sharing actions and reducers with react/redux

我仍然是一个反应/redux 菜鸟。 在一页上,我有大量的文本输入。 一段时间后,我开始注意到我的操作文件具有执行相同操作但用于不同输入的函数:

export function setInputName(string) {
  return {
    type: 'SET_CURRENT_NAME',
    payload: {value: string}
  };
}
export function setInputCity(string) {
  return {
    type: 'SET_CURRENT_CITY',
    payload: {value: string}
  };
}

我的减速机看起来像:

export function currentName(state='', {type, payload}) {
  switch (type) {
  case 'SET_CURRENT_NAME':
    return payload.value;
  default:
    return state;
  }
}
export function currentCity(state='', {type, payload}) {
  switch (type) {
  case 'SET_CURRENT_CITY':
    return payload.value;
  default:
    return state;
  }
}

我的组件有这些多个输入:

import {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {setInputName, setInputCity} from 'actions/form';

export default class Form extends Component {
  static propTypes = {
    setInputName: PropTypes.func.isRequired,
    setInputCity: PropTypes.func.isRequired,
    currentName: PropTypes.string.isRequired,
    currentCity: PropTypes.string.isRequired
  }
  render() {
    let {setInputName, setInputCity, currentName, currentCity} = this.props;
    return (
      <div>
        <input
          type="text" 
          placeholder="Name"
          onChange={(e) => setInputName(e.currentTarget.value)}
          value={currentName}
        />
        <input
          type="text" 
          placeholder="City"
          onChange={(e) => setInputCity(e.currentTarget.value)}
          value={currentCity}
        />
      </div>
    );
  }
}

function select(state) {
  return {
    currentName: state.form.currentName,
    currentCity: state.form.currentCity
  };
}

function actions(dispatch) {
  return bindActionCreators({
   setInputName: setInputName,
   setInputCity: setInputCity,
  }, dispatch);
}

export default connect(select, actions)(Form);

这不是很干燥,我立即认为我做错了什么。 有没有一种好方法可以为我的应用程序的每个页面和组件上的所有文本输入设置一个通用的setInputValue操作? 我还想为每个输入使用一个通用的减速器。 谢谢你。

更新

这是我的粗略示例,但我觉得这仍然有点令人费解,必须有更好的方法。 基本上在减速器中,我检查该输入是否已被使用并添加到状态中。 如果没有我添加它。 如果是这样,我只是更新它的值。 编辑我撒谎这实际上不起作用。

// actions
export function updateTextInput(name, value) {
  return {
    type: 'SET_CURRENT_TEXT_INPUT',
    payload: {name: name, value: value}
  };
}

// reducer
export function currentTextInput(state=[], {type, payload}) {
  switch (type) {
  case 'SET_CURRENT_TEXT_INPUT':
    let newState = state;
    let curInput = state.findIndex(function(elem) {
      return elem.name === payload.name;
    });
    if (curInput === -1) {
      newState.push({name: payload.name, value: payload.value});
    } else {
      newState[curInput].value = payload.value;
    }
    return newState;
  default:
    return state;
  }
}

// component
...
render() {
  let {updateTextInput, currentTextInput} = this.props;
  return (
    <div>
      <input
        type="text" 
        placeholder="Name"
        onChange={(e) => updateTextInput('name', e.currentTarget.value)}
        value={currentTextInput.name}
      />
      <input
        type="text" 
        placeholder="City"
        onChange={(e) => updateTextInput('city', e.currentTarget.value)}
        value={currentTextInput.city}
      />
    </div>
  );
}
...

简化代码的第一步是使用高阶化简器/函数。

function makePropReducer(actionType, prop) {
  return (state = '', {type, payload}) => {
    if (type === actionType) {
      return payload[prop];
    }
    return state;
  };
}

export const currentName = makePropReducer('SET_CURRENT_NAME', 'value');
export const currentCity = makePropReducer('SET_CURRENT_CITY', 'value');

好的,这是一个应要求的示例。 假设我有一个 User 数据模型,它看起来像这样:

{
  id: 1,
  name: 'Some Name',
  email: 'someemail@some.com',
  age: 21
}

您当前设置的方式必须有 SET_USER_NAME、SET_USER_EMAIL、SET_USER_AGE 操作。 当您可以使用 UPDATE_USER 操作接收更新值的对象作为参数时,不需要所有这些。

要为第一个用户设置新名称,您可以调用 UPDATE_USER 操作,例如:

updateUser(1, { name: 'New Name' })

在用户减速器中,您将更新用户的状态(用户数组),例如:

function updateUser(usersState, id, attrs) {
  return usersState.map(user =>
    user.id === id ?
    Object.assign({}, user, attrs) :
    user
  );
}

我最近想出了这样的动作,

export function controlStateChange(controlName, propertyName, value) {
  return { type: 'CONTROL_STATE_CHANGE', payload: { controlName, propertyName, value } };
}

和相应的减速机,

const actionHandlers = {
  'CONTROL_STATE_CHANGE': (state, payload) => {
    const controls = {
      [payload.controlName]: {
        [payload.propertyName]: payload.value
      }
    };

    return {...state, controls };
  }
};

它很一般,我希望也能满足您的需求。

为了将输入保存到状态,您可以使用redux-form

看来您的问题与共享减速器/操作并没有真正相关。 对于共享操作/reducers,我写了一个,你可以看看redux-conditional

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM