reactjs - React Select 与自定义 MultiValueContainer 和 Apollo Mutation 不合作

标签 reactjs apollo react-apollo apollo-client react-select

我有一个使用 Apollo 和 React-Select 的自定义组件,并且有两个突变(见下文)。 react 选择是多值的,需要自定义,因为我需要一个“isSelected”复选框。此代码中未显示,但初始选项列表是从父容器传入的。

父 Select 及其突变按预期工作。但是,我在自定义 MultiValueContainer 方面遇到了一些奇怪的问题。第一个是,当我第一次选择任何复选框时,我收到一条错误消息,指出“无法在未安装的组件上调用 setState(或forceUpdate)”。请注意,下面我有一个空的 componentWillUnmount 函数,只是为了查看它是否被调用,但事实并非如此。但是(我假设)因此,当调用“toggleThing”突变时,状态没有完成请求所需的变量。第二次单击时,它按预期工作,但第二个问题除外。

第二个问题是 MultiValueContainer 突变上的 onCompleted 函数永远不会触发,因此即使服务器返回预期数据,它似乎也永远不会返回到突变,因此永远不会返回到组件。父 Select 上的 onCompleted 函数按预期工作。

预先感谢任何人可能有的见解。也许不用说,我对react/apollo/react-select还比较陌生,对于任何新手错误提前道歉。另外,我尝试清理和简化代码,因此对于任何重命名错误也表示歉意。

const UPDATE_THINGS = gql`
    mutation UpdateThings(
        $id: ID!
        $newThings: [ThingInput]
    ) {
        updateThings(
            id: $id
            newThings: $newThings
        ) {
            id
        }
    }
`;

const TOGGLE_THING = gql`
    mutation ToggleThing($id: ID!, $isChecked: Boolean) {
        toggleThing(
            id: $id
            isChecked: $isChecked
        ) {
            id
        }
    }
`;

class ThingList extends Component {
    stylesObj = {
        multiValue: base => {
            return {
                ...base,
                display: 'flex',
                alignItems: 'center',
                paddingLeft: '10px',
                background: 'none',
                border: 'none'
            };
        }
    };

    constructor(props) {
        super(props);

        this.state = {
            selectedThings: [],
            selectedThingId: '',
            selectedThingIsChecked: false
        };
    }

    onUpdateComplete = ({ updateThings }) => {
        console.log('onUpdateComplete');
        console.log('...data', updateThings );
        this.setState({ selectedThings: updateThings });
    };

    onToggleThing = (thingId, isChecked, toggleThing) => {
        console.log('onToggleThing, thingId, isChecked');

        this.setState(
                {
                    selectedThingId: thingId,
                    selectedThingIsChecked: isHighPisCheckedoficiency
                },
                () => toggleThing()
            );
    };

    onToggleThingComplete = ({ onToggleThing }) => {
        console.log('onToggleThingComplete ');
        console.log('...data', onToggleThing );
        this.setState({ selectedThings: onToggleThing });
    };

    handleChange = (newValue, actionMeta, updateThings) => {
        this.setState(
            {
                selectedThings: newValue
            },
            () => updateThings()
        );
    };

    isThingSelected = thing=> {
        return thing.isSelected;
    };

    getSelectedThings = selectedThings => {
        console.log('getSelectedSkills');
        return selectedThings ? selectedThings.filter(obj => obj.isSelected) : [];
    };

    componentWillUnmount() {
        console.log('componentWillUnmount');
    }

    render() {
        const self = this;
        const MultiValueContainer = props => {
            // console.log('...props', props.data);
            return (
                <Mutation
                    mutation={ TOGGLE_THING }
                    onCompleted={self.onToggleThingComplete}
                    variables={{
                        id: self.state.selectedThingId,
                        isChecked: self.state.selectedThingIsChecked
                    }}>
                    {(toggleThing, { data, loading, error }) => {
                        if (loading) {
                            return 'Loading...';
                        }

                        if (error) {
                            return `Error!: ${error}`;
                        }

                        return (
                            <div className={'option d-flex align-items-center'}>
                                <input
                                    type={'checkbox'}
                                    checked={props.data.isChecked}
                                    onChange={evt => {
                                        self.onToggleThing(
                                            props.data.id,
                                            evt.target.checked,
                                            toggleIsHighProficiency
                                        );
                                    }}
                                />
                                <components.MultiValueContainer {...props} />
                            </div>
                        );
                    }}
                </Mutation>
            );
        };

        return (
            <Mutation
                mutation={UPDATE_THINGS}
                onCompleted={this.onUpdateComplete}
                variables={{ id: this.id, newThings: this.state.selectedThings}}>
                {(updateThings, { data, loading, error }) => {
                    if (loading) {
                        return 'Loading...';
                    }

                    if (error) {
                        return `Error!: ${error}`;
                    }

                    return (
                        <div>
                            <Select
                                options={this.props.selectedThings}
                                styles={this.stylesObj}
                                isClearable
                                isDisabled={this.props.loading}
                                isLoading={this.props.loading}
                                defaultValue={this.props.selectedThings.filter(
                                    obj => obj.isSelected
                                )}
                                isOptionSelected={this.isOptionSelected}
                                isMulti={true}
                                onChange={(newValue, actionMeta) =>
                                    this.handleChange(
                                        newValue,
                                        actionMeta,
                                        updateThings
                                    )
                                }
                                components={{
                                    MultiValueContainer
                                }}
                            />
                        </div>
                    );
                }}
            </Mutation>
        );
    }
}

export default ThingsList;

最佳答案

您在每个render 上重新定义MultiValueContainer,这不是一个好的做法,并且可能会导致意外行为。尝试将其移至单独的组件中,看看是否有帮助。

关于reactjs - React Select 与自定义 MultiValueContainer 和 Apollo Mutation 不合作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52412808/

相关文章:

javascript - 链接查询树,不包含 "Rendered more hooks than during the previous render"

用于 C++ 和 .NET 的 GraphQL 客户端

javascript - React - Apollo Client,如何将查询结果添加到状态

c# - Apollo Stomp ActiveMQ 创建无效的临时目的地名称

javascript - 如何检测页面中使用的 JS 框架/库?

javascript - 无法在渲染方法react js中进行条件渲染

javascript - redux 文档对于 mapStateToProps 意味着什么?

reactjs - React Apollo MockProvider 总是加载,从不提供数据

react-apollo - RN Apollo Client 3.0 - 使用合并功能处理重新获取

node.js - 使用 Browserify 和 React 导入 Node 模块的循环依赖关系