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

React Select with Custom MultiValueContainer and Apollo Mutation not Cooperating

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

父代 Select 及其突变按预期工作。但是,我 运行 遇到了自定义 MultiValueContainer 的一些奇怪问题。第一个是我第一次 select 任何复选框时,我得到一个错误说 "Can't call setState (or forceUpdate) on an unmounted component." 请注意下面我有一个空的 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,这不是一个好的做法,可能会导致意外行为。尝试将其移动到单独的组件中,看看是否有帮助。