如何将状态添加到动态UI控件中?

时间:2019-06-20 13:50:45

标签: javascript json reactjs jsx

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

Uncaught TypeError: _this.setState is not a function

我基本上从一支笔基于JSON递归生成UI控件中获得了一个非常好的样本-我已经将它们设为受控组件(通过向控件添加value / checked属性)。

这一切都很好,但是,不会更新任何UI控件(因此,如果最初选中该复选框,则不会在UI中取消选中该复选框)。因此,要解决此问题,我现在尝试向其添加State,以使UI正常工作。我真的不确定这是否是正确的方法,还是应该只使它们成为所有不受控制的组件并使用引用-但这显然不是最佳方法,根据react文档。

我在onChange上添加了一个InputGroup事件。这会调用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}/>
        )
    }
}

例如,当用户单击某个复选框,它重新呈现状态并更新UI时,我希望能够(有时)调用setState,因此该复选框取消选中或签入用户界面。

它的实际作用是在setState上发生错误-因此,即使onChange事件触发并且我可以选择更改的值,UI也不会得到更新。注意:如果我完全删除“状态”的设置,则UI不会更新,这就是为什么要将“状态”添加到解决方案中的原因。

1 个答案:

答案 0 :(得分:0)

您正在呼叫this.inputChangedHandler,但请注意,InputGroup不是class,而是function

此外,常规函数中没有setState,这是通过创建扩展class的{​​{1}}来获得的方法

简而言之,如果您想要React.Component(或任何其他反应特定功能),则需要使用setState并从React.Component扩展

这就是它应该多少看起来像:

class