首页 > 解决方案 > 如何将状态添加到动态 UI 控件中?

问题描述

我正在尝试为使用 ReactJS 创建的一些动态 UI 控件添加一些状态。我收到错误

Uncaught TypeError: _this.setState is not a function

我基本上从基于一些 JSON 的递归生成 UI 控件的笔中得到了一个非常好的示例——我已经将它们制成了受控组件(通过向控件添加值/检查属性)。

这一切都很好,但是,没有任何 UI 控件更新(因此,如果最初选中的复选框不会在 UI 中取消选中)。所以为了解决这个问题,我现在尝试向它添加状态,以便 UI 正常工作。我真的不确定这是否是正确的方法,或者我是否应该将它们全部设为不受控制的组件并使用参考 - 但根据反应文档,这显然不是最佳实践。

我已经onChangeInputGroup. 这调用inputChangedHandler函数,在这我试图setState- 这是我得到错误的地方

Uncaught TypeError: _this.setState is not a function

在这条线上:

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

我认为它在这一点上失败的原因是没有setState方法,this所以我不确定如何通过正确的“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在用户(例如)单击复选框时(在某个时候)调用,它会重新呈现状态并更新 UI - 因此复选框取消选中或选中 UI。

它实际上在做的是错误setState- 所以影响是 UI 没有更新,即使onChange事件触发并且我可以获取更改的值。注意:如果我完全删除“状态”的设置,那么 UI 不会更新,这就是我想在我的解决方案中添加“状态”的原因。

标签: javascriptjsonreactjsjsx

解决方案


您正在打电话this.inputChangedHandler,但请注意InputGroup不是 aclass而是 a function

此外,没有setState内部常规函数,这是您通过创建class扩展的方法获得的React.Component

简而言之,如果您想要setState(或任何其他特定于反应的功能),您将需要使用 aclass并从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>
        )
    }
}

推荐阅读