一次触发一个时方法正确呈现,但未在React-Redux容器中使用_.map [英] Method renders correctly when triggered one at a time, but not using _.map in React-Redux container

查看:56
本文介绍了一次触发一个时方法正确呈现,但未在React-Redux容器中使用_.map的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有React-Redux容器,其中动态生成了一堆按钮.它们下方是全选和清除选择按钮.单击按钮后,它将被发送到setState按钮处于活动状态的方法,并将有关所选按钮的信息发送到action,该信息确定如何在按钮下方呈现内容.

I have React-Redux container where a bunch of buttons are dynamically generated. Below them are Select All and Clear Selection buttons. When a button is clicked, it is sent to a method where it setState that the button is active and sends information about the selected button to an action that determines how things are rendered below the buttons.

无论如何,当我一次选择一个按钮时,它会添加到state并允许选择多个按钮.当我使用全选"时,它只会选择最后一个按钮.在这两种情况下,按钮的value都一次作为一个字符串传递给方法(至少我很确定_.map本质上就是这样做的),所以不确定为什么这不是工作.

Anyway, when I select a button one at a time, it adds to the state and permits the selecting of multiple buttons. When I use Select All, it only selects the last button. In both cases, the value of the button is being passed to the method as a string one at a time (at least I am pretty sure that is what _.map is essentially doing), so not sure why this isn't working.

class BasicQueryCuts extends Component {
    constructor(props) {
        super(props);
        this.state = {
            cuts: {}
        }

        this.selectAll = this.selectAll.bind(this);
    }

    // This is where state is being set and data sent to the Redux store
    // It affects how some other components are rendered
    onCutSelect(cut) {
        let cuts = {...this.state.cuts, [cut]: cut}
        this.setState({
            cuts
        }, () => this.props.basicQueryResults(this.state.cuts));
    }

    // The select all where it should basically take what is the value
    // of rendered buttons and pass it to the onCutSelect method
    // However, this will only actually select the last button.
    selectAll() {
        const { data } = this.props;
        _.map(
            data, c => {
                this.onCutSelect(c.Cut);
            }
        )        
    }

    // These buttons will allow selecting everything, or clearing the selection
    renderAllNothingButtons() {
        const { data } = this.props;

        // generate the list of cuts
        if (data) {
            return (
                <Row>
                    <Col>
                        <Button color='primary' className='cuts-btn' onClick={this.selectAll}>
                            Select All
                        </Button>
                    </Col>
                    <Col>
                        <Button color='danger' className='cuts-btn' onClick={this.clearSelection}>
                            Clear All
                        </Button>
                    </Col>
                </Row>
            )            
        }
    }

    // Render the individual buttons
    // Selecting one at a time does work as expected: it adds to state
    renderCutsButtons() {
        const { data } = this.props;

        return (
            <Row>
                {_.map(
                    data, c => {
                        return (
                            <Col>
                                <Button 
                                    className={this.state.cuts.hasOwnProperty(c.Cut) ? 'cuts-btn-active' : 'cuts-btn'}
                                    key={c.Cut}
                                    value={c.Cut}
                                    onClick={event => this.onCutSelect(event.target.value)}
                                >
                                    {c.Cut}
                                </Button>
                            </Col>
                        )   
                    }
                )}
            </Row>
        )
    }

    render() {
        // In the case of selecting one button at a time it will print:
        // {Cut1: "Cut1", Cut2: "Cut2", etc.}
        // In the case of using Select All, it will just print the last:
        // {CutLast: "CutLast"}
        console.log(this.state.cuts);
        return (
            <div className='results-bq-cuts'>
                {this.renderCutsButtons()}
                {this.renderAllNothingButtons()}
            </div>
        )
    }
}

推荐答案

代码可能还有其他问题,但是可以解释此行为的一个问题是setState的updater-object参数cuts呼叫指的是this.state.

There might be some other problems with the code, but one problem that can explain this behavior is that the updater-object parameter cuts to the setState call refers to this.state.

React事件处理程序中的setState调用不会立即更新状态,而是将更新排队.在事件处理程序完成后的某个时刻,将处理这些批处理的更新以计算新状态.这意味着当您多次调用onCutSelect时,会将一系列更新排入队列,每个更新将cuts替换为原始cuts的副本,且仅更新了一个剪切.处理完这些更新后,最后的更新将获胜,并且仅选择了最后一个按钮.

A setState call in a React event handler does not immediately update the state, but rather queues the update. At some point after your event handler finishes, these batched updates are processed to compute the new state. This means that when you call onCutSelect multiple times, you queue a series of updates, which each replace cuts by a clone of the original cuts with only one cut updated. When these updates are processed, the last update wins, and only the last button is selected.

解决方案是使用更新程序 function 而不是对象:

The solution is to use an updater function instead of an object:

this.setState((prevState, props) => ({/* state update */}))(请参见 setState文档).

this.setState((prevState, props) => ({/* state update */})) (see the setState docs).

更新程序功能将获取由于应用以前的更新而导致的最新状态,因此您可以递增地更新每个切割.在您的代码中,您可以执行以下操作:

The updater function will get the up-to-date state resulting from applying previous updates, so you can incrementally update each cut. In your code you can do something like this:

onCutSelect(cut) {
    this.setState(
      ({cuts: prevCuts}) => ({cuts: {...prevCuts, [cut]: cut}}),
      () => this.props.basicQueryResults(this.state.cuts)
    );
}

此外,如果this.props.data是数组,则可以简单地使用this.props.data.map((c) => ..).无需使用lodash或下划线.

Also, if this.props.data is an array, you can simply use this.props.data.map((c) => ..). No need to use lodash or underscore.

这篇关于一次触发一个时方法正确呈现,但未在React-Redux容器中使用_.map的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆