在redux中调度操作后获取更新状态

时间:2016-11-27 11:05:32

标签: reactjs redux

我正在使用react和redux。

我有一个如下定义的Container组件:

import { connect } from 'react-redux';
import {addTag} from 'actions';
import ExpenseTagsControl from './expense_tags_control'

const mapStateToProps = (state, own_props={selected_tags:[]}) => {
    return {
        tags_list: state.tags.tags_list
    };
};


const mapDispatchToProps = (dispatch) => {
    return {
        addTag: (tag_name) => {
            dispatch(addTag(tag_name))
        }
    };
};

const AddExpenseTagsContainer = connect(
  mapStateToProps,
  mapDispatchToProps
)(ExpenseTagsControl);


export default AddExpenseTagsContainer;

容器包装一个表示组件,其定义如下:

// expense_tags_control.js
import React, {Component, PropTypes} from 'react';
import ChipInput from 'material-ui-chip-input';
import Chip from 'material-ui/Chip';
import Avatar from 'material-ui/Avatar';
import Tag from 'common/svg_icons/tag';
import AutoComplete from 'material-ui/AutoComplete'

import _ from 'underscore';



class ExpenseTagsControl extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            chips: []
        };
    };

    handleAdd(chip) {

          // If the chip does not already exist, add it. the id here will be a dummy value that is not there in the tags_list
        if (!(_.contains( _.map(this.props.tags_list, (tag) => tag.id), chip.id))) {
            this.props.addTag(chip.name);
        }

          // This is wrong.     
        this.setState({
            chips: [...this.state.chips, chip]
        });
    };

    handleDelete(chip) {
        this.setState({
            chips: this.state.chips.filter((c) => c !== deletedChip)
        });
    };


    chipRenderer({ text, value, isFocused, isDisabled, handleClick, handleRequestDelete }, key) {
        const style = {
            margin: '8px 8px 0 0',
            float: 'left',
            pointerEvents: isDisabled ? 'none' : undefined
        };

        return (
            <Chip key={key} style={style} onTouchTap={handleClick} onRequestDelete={handleRequestDelete}>
                <Avatar size={24} icon={<Tag />} />
                {text}
            </Chip>
        );
    };

    render() {
        return (
            <ChipInput
                hintText="Tags"
                value={this.state.chips}
                onRequestAdd={(chip) => this.handleAdd(chip)}
                onRequestDelete={(deletedChip) => this.handleDelete(deletedChip)}
                fullWidth={true}
                dataSourceConfig={{ text: 'name', value: 'id' }}
                dataSource={this.props.tags_list}
                chipRenderer={this.chipRenderer}
                openOnFocus={false}
                filter={AutoComplete.fuzzyFilter}
                onRequestDelete={console.log("Deleted")}
            />);
    };
};

ExpenseTagsControl.PropTypes = {
    tags_list: PropTypes.array.isRequired,
    addTag: PropTypes.func.isRequired,
    value: PropTypes.array.isRequired,
    onChange: PropTypes.func.isRequired
};

export default ExpenseTagsControl;

上面的表示组件保持一个状态,表示已经选择的芯片。

ChipInput组件允许您选择具有id的对象的芯片,以及从预先存在的数据源定义的名称。该组件还允许您通过键入名称来添加新芯片。如果数据源中不存在键入的名称,则会将其添加到数据源中。

我的问题

一旦调度addTag()动作,就会分配新添加的芯片的ID。如何获取刚刚调度的操作结果的值?

我考虑通过在全局状态下维护ChipInput的状态来解决这个问题,并在调度addTag()动作时操纵全局状态。但这感觉太多了。

2 个答案:

答案 0 :(得分:1)

如果我理解的是正确的,你可能需要这样的东西:

class ExpenseTagsControl extends React.Component {

    // ...


    /*
     * assuming your reducers are working fine and 'addTag'
     * has updated global 'state.tags.tags_list'
     */
    componentWillReceiveProps(nextProps) {
        this.setState({ chips: this.nextProps.tags_list });
    }

    // ...
}

NB:您可能需要根据某些条件优化setState内的componentWillReceiveProps调用,以避免不必要的重新渲染。

答案 1 :(得分:1)

根据我的理解,OP的问题是如何分派修改redux存储的操作,同时更新组件的本地状态。

编辑:添加了一个实例

&#13;
&#13;
const initialState = {
  tags: ['hello', 'hi', 'howdy']
}

function reducer(state = {}, action) {
  switch (action.type) {
    case 'ADD_TAG':
      return {
        ...state,
        tags: [
          ...state.tags,
          action.payload.tag
        ]
      }
    default:
      return state;
  }
}

const store = Redux.createStore(reducer, initialState);

const addTag = (tag) => ({
  type: 'ADD_TAG',
  payload: {
    tag
  }
})

class Chips extends React.Component {
    constructor(props) {
      super(props);
      this.chipToAdd = false;
      this.state = {
        chips: []
      }
      this.handleAdd = this.handleAdd.bind(this);
    }

    componentWillReceiveProps(nextProps) {
      console.log(this.chipToAdd);
      if (this.chipToAdd) {
        this.setState({
          chips: [...this.state.chips, this.chipToAdd]
        }, (this.chipToAdd = false));
      }
    }

    handleAdd(chip) {
      if (this.props.tags.filter(tag => tag === chip).length === 0) {
        this.chipToAdd = chip;
        this.props.addTag(chip);
      } else {
        if (this.state.chips.filter(existingChip => existingChip === chip).length === 0) {
          this.setState({
            chips: [...this.state.chips, chip]
          });
        }
      }
    }

    render() {
        return <div >
          < h3 > Tags added in component 's chip state</h3>
			<ul>
				{this.state.chips.map((chip, index) => <li key={index}>{chip}</li>)}
			</ul>
			<hr />
			<h3>Tags in Redux Store</h3>
			{this.props.tags.map(
				(tag, index) => <li key={index}>
					{tag} <button onClick={() => this.handleAdd(tag)}>Add</button>
				</li>
			)}
			<button onClick={() => this.handleAdd('
        new tag - ' + Math.floor((Math.random() * 100) + 1))}>Add a chip with new tag</button>
		</div>
	}
}

const mapStateToProps = ({ tags = [] }) => ({ tags });
const ConnectedChips = ReactRedux.connect(mapStateToProps, { addTag })(Chips);

class App extends React.Component {
	render() {
		return <div>
			<h1>React/Redux Demo</h1>
			<ConnectedChips />
		</div>
	}
}

const Provider = ReactRedux.Provider;

ReactDOM.render(
    <Provider store={store}><App /></Provider>,
    document.getElementById('
        root ')
);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://unpkg.com/redux@3.6.0/dist/redux.min.js"></script>
<script src="https://unpkg.com/react-redux@4.4.6/dist/react-redux.min.js"></script>
<div id="root"></div>
&#13;
&#13;
&#13;