Как добавить состояние в динамические элементы управления пользовательского интерфейса? - PullRequest
1 голос
/ 20 июня 2019

Я пытаюсь добавить состояние в некоторые динамические элементы управления пользовательского интерфейса, созданные с помощью ReactJS. Я получаю ошибку

Uncaught TypeError: _this.setState is not a function

Я в основном получил действительно хороший образец из пера рекурсивного генерирования элементов управления пользовательского интерфейса на основе некоторого JSON - я сделал их управляемыми компонентами (добавив значения / свойства в элементах управления).

Это все хорошо, однако ни один из элементов управления пользовательского интерфейса не обновляется (поэтому флажок не снимает флажок в пользовательском интерфейсе, если он изначально установлен). Поэтому, чтобы исправить это, я сейчас пытаюсь добавить к нему State, чтобы пользовательский интерфейс работал правильно. Я действительно не уверен, что это правильный путь или я должен просто сделать их все неконтролируемыми компонентами и использовать ссылки - но это, очевидно, не лучшая практика в соответствии с документацией реагирования.

Я добавил в onChange событие на InputGroup. Это вызывает inputChangedHandler функцию, и в этом я пытаюсь setState - вот где я получаю ошибку

Uncaught TypeError: _this.setState is not a function

в этой строке:

this.setState({ input: event.target.checked });

Я думаю, что причина, по которой он терпит неудачу на этом этапе, заключается в том, что на this нет метода setState, поэтому я не уверен, как пройти через правильное 'this'. Я инициализировал состояние внутри конструктора, что я считаю правильным решением. Я думаю, что это просто вопрос возможности использовать этот setState метод на правильном this.

//Component defined for text, date, numeric and checkbox)
const InputGroup = props => { 
    const types = { "Text": 'text', "Date": 'date', "Numeric": "number", "CheckBox": "checkbox" }
    return (
         //The props.value relates to JSX attribute names for the inputgroup below
        <div className="input-groupDynamic">
            <label className="labelD" htmlFor={props.label.replace(" ", "-")}>{props.label}</label>
            <input name={props.label.replace(" ", "-")}
                type={types[props.type]}

                //uncontrolled components code
                //defaultValue={props.value}
                //defaultChecked={props.value}

                //controlled components code
                value={props.value}
                checked={props.value}
                onChange={this.inputChangedHandler.bind(this)}
            />
        </div>
    )
}

//arrow function 
inputChangedHandler = (event) => {
    if (event.target.type == 'checkbox') {
        alert('new value : ' + event.target.checked);

        this.setState({ saveCareersUrlVisible: event.target.checked });

    } else {
        alert('new value : ' + event.target.value);
    }
}

//arrow function 
inputChangedHandler = (event, data) => {
    if (event.target.type == 'checkbox') {
        this.setState({ input: event.target.checked });

    } else {
        //to do....
    }
}

const renderChildren = children => {    
    //This is the bit that does a recursive-ish rendering of children....using the .map to map over the JSON data return children? children.map((child, ind) => {

        //Using 'const' as the variable won’t be reassigned.
        const newChildren = child.children ? [...child.children] : [];
        const { containerType, title, input, label, options, value, ref } = child

        //Using 'let' as this is a variable that may be reassigned
        let key;  
        let actualDate;

        if (typeof (input) !== 'undefined' && input == "Date" && typeof (value) !== 'undefined') {
            //console.log("control type : " + input);
            actualDate = new Date(value).toISOString().substr(0, 10);
        }
        //console.log("Date from JSON :" + (typeof (date) !== 'undefined' ? date : '2001-01-01'));
        //console.log("Converted Date:" + test.toString());
        //console.log("initial date value: " + date);
        if (newChildren.length) {
            key = `${containerType}-${ind}`;
            switch (containerType) {    
                case "Tabs":
                    return <Tabs
                        key={key}
                        title={title}
                        children={newChildren}
                    />
                case "Column":
                    return <Column
                        key={key}
                        title={title}
                        children={newChildren}
                    />
                case "Row":
                    return <Row
                        key={key}
                        title={title}
                        children={newChildren}
                    />
                default:
                    return <Common
                        key={key}
                        title={title}
                        children={newChildren}
                    />
            }
        } else {
            console.log("control type : " + input);
            console.log("ref : " + ref);

            key = `${input}-${ind}`
            console.log("key : " + key);

            switch (input) {
                case "ComboBox":
                    return <SelectGroup
                        key={key}
                        label={label}
                        options={options}
                    />
                case "Text":
                case "Numeric":
                    return <InputGroup
                        key={key}
                        label={label}
                        type={input}
                        value={value}
                        //ref={ref}
                    />
                case "Date":
                    return <InputGroup
                        key={key}
                        label={label}
                        type={input}
                        value={actualDate}
                        //ref={key}
                    />
                case "CheckBox":
                    return <InputGroup
                        key={key}
                        label={label}
                        type={input}
                        value={value}
                        //onChange={e => this.setState({ SaveCareersUrlVisible: props.label.replace(" ", "-" + e.value) })}
                    />
                case "Button":
                    return <ButtonGroup
                        key={key}
                        type={input}
                        onClick={(e) => this.handleSubmitClick(e)}
                    ></ButtonGroup>
            }
        }

    }) : null
}

class App extends React.Component {
    //Class constructor 
    constructor(props) {
        // Pass props to the parent component
        super(props)
        // Set initial state, use spread notation and pass entire object (the JSON data in this case) - this will unpack it into the props
        this.state = {
            saveCareersUrlVisible: "",
            ...props.config
        }; 
    }

    componentDidMount() {
        alert("componentDidMount");
    }

    handleSubmitClick = (event) => {
        event.preventDefault();
        const data = new FormData(event.target);

        this.setState({
            myvalues: stringifyFormData(data),
        });
    }

    render() {
        const { title, children, saveCareersUrlVisible } = this.state;
        return (
            <Container title={title} children={children} saveCareersUrlVisible={saveCareersUrlVisible}/>
        )
    }
}

Я ожидаю, что смогу вызвать setState (в какой-то момент), когда пользователь, например, нажимает на флажок, он повторно отображает состояние и обновляет пользовательский интерфейс - поэтому флажок снимает или проверяет в пользовательском интерфейсе .

То, что он на самом деле делает, это ошибка на setState - так что влияние заключается в том, что пользовательский интерфейс не обновляется, даже если происходит событие onChange, и я могу подобрать измененное значение. Примечание. Если полностью удалить настройку «состояние», пользовательский интерфейс не будет обновлен, поэтому я хочу добавить «состояние» в свое решение.

1 Ответ

0 голосов
/ 20 июня 2019

Вы звоните this.inputChangedHandler, но учтите, что InputGroup это не class, а function.

Кроме того, внутри обычных функций нет setState, это метод, который вы получаете, создавая class, который расширяет React.Component

Короче говоря, если вы хотите setState (или любые другие специфические для реагирования функции), вам нужно будет использовать class и расширять с React.Component

Так вот как это должно выглядеть более или менее:

class InputGroup extends React.Component {

    state = { saveCareersUrlVisible: false } // initial state

    //arrow function 
    inputChangedHandler = (event) => {
        if (event.target.type == 'checkbox') {
            alert('new value : ' + event.target.checked);

            this.setState({ saveCareersUrlVisible: event.target.checked });

        } else {
            alert('new value : ' + event.target.value);
        }
    }

    render() {
        const types = { "Text": 'text', "Date": 'date', "Numeric": "number", "CheckBox": "checkbox" }
        return (
            //The props.value relates to JSX attribute names for the inputgroup below
            <div className="input-groupDynamic">
                <label className="labelD" htmlFor={this.props.label.replace(" ", "-")}>{this.props.label}</label>
                <input name={this.props.label.replace(" ", "-")}
                    type={types[this.props.type]}

                    //uncontrolled components code
                    //defaultValue={props.value}
                    //defaultChecked={props.value}

                    //controlled components code
                    value={this.props.value}
                    checked={this.props.value}
                    onChange={this.inputChangedHandler.bind(this)}
                />
            </div>
        )
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...