反应组件的更改未在视图中显示-一个字符更改显示在onChange

时间:2018-07-30 16:44:22

标签: reactjs typescript dom hoisting

问题:

我似乎无法更改输入标签(在<Details />内部)中的占位符。

预期行为:

将使用组件的状态及其handleChange函数来更新输入标签。

实际行为:(很抱歉,正在处理中!

对输入字段所做的更改仅注册一个字符。

示例:选择FileName中的所有字符并将其删除显示为console.log()函数中的handleChange中已删除的字符。但是,该字段永远不会在视图上更改,而是具有相同的值。

我尝试过的事情:

我尝试使用propsstate处理更改,但是没有任何效果。我猜想我可能像我对FileItem所做的那样,将更改提升到祖先,但是我不确定。

实际代码:

import * as React from "react";
import { IFileModel, IFileWrapper } from "../models/fileModel";
import { Fortress } from "../../dependencies/fortress";

let divStyle = {
    width: "50px",
    border: "1px solid #000",
    padding: "5px",
    margin: "5px"
};

declare let config : {[key : string] : string};

const $F = new Fortress(config);

export class DetailsPanel extends React.Component<IFileModel, any> {
    constructor(props : IFileModel) {
        super(props); 
        this.state = { 
            isDisplayed : false 
        };
        this.toggle = this.toggle.bind(this);  
    }  

    toggle() {
        let newIsCollapsed = !(this.state.isDisplayed);
        this.setState({ isDisplayed : newIsCollapsed })
    }   

    render() {
        return(
            <div>
                <div>
                    <input className="button" type="submit" value={ (!this.state.isDisplayed) ? "Show Panel" : "Hide Panel" } onClick={this.toggle} />
                </div>
                { this.state.isDisplayed ? <Details {...this.props} /> : null }
            </div>
        );
    }
}

export class Details extends React.Component <IFileModel, any> {

    constructor(props : IFileModel) {
        super(props);
        this.state = {
            currentFile : this.props
        };
        this.onSubmit = this.onSubmit.bind(this);
        this.handleChange = this.handleChange.bind(this);
    }
    // http://localhost/admin/shared/file/SaveFile/?
    /*
        FileId: 1
        FileName: shirt.pdf
        LCID: 2057
        FileVariation: 0
        DisplayName: shirt.png
        OriginalFileName: shirt__1_3_2057.pdf
        CategoryId: 0
        FileType: 1
        FileExtension: png
        FileSize: 419920
        Width: 615
        Height: 462
        FileData: 
        AllowedVariantTypes: 0
        RequireAuthorization: 0
        AdminId: 1
        CreationDate: /Date(1450692426023)/
        ModifyDate: /Date(1450692426023)/
        ExpiryDate: /Date(253402300799997)/
    */

    handleChange(e : any) { 
        console.log(e.target.name, e.target.value);
        this.setState({ [e.target.name] : e.target.value });
    }

    onSubmit() {
        const state = this.state.currentFile;
        console.log($F.writeAdminUrl("shared", "file", "SaveFile"));
        console.log(JSON.stringify(state));
        // fetch($F.writeAdminUrl("shared", "file", "SaveFile"), {
        //     method: "POST",
        //     headers: {
        //         "credentials": "same-origin", 
        //         "mode": "no-cors",
        //         "Content-Type" : "application/json"
        //     },
        //     body : JSON.stringify({ fileId : state.fileId })
        // })
    }

    render() {
        const currentFile = this.props;
        return(
            <div style={{border: "1px dashed black", padding: "4px"}}>
                <div>
                    <p> File Name: </p>
                    <input type="text" value={currentFile.fileName} name="fileName" onChange={this.handleChange} />
                </div>
                <div>
                    <p> Image: </p>
                    <input type="text" value={currentFile.imageUrl} name="imageUrl" onChange={this.handleChange} />
                </div>
                <div>
                    <p> Creation date: </p>
                    <input type="text" value={currentFile.creationDate} name="creationDate" onChange={this.handleChange} />
                </div>
                <div>
                    <p> LCID: </p>
                    <input type="text" name="LCID" value={currentFile.LCID} onChange={this.handleChange} />
                </div>
                <div>
                    <input onClick={(currentFile) ? this.onSubmit : null} type="submit"/>
                </div>
            </div>
        );
    }
}

export class FileItem extends React.Component<IFileModel> {

    constructor(props : IFileModel) {
        super(props);
        this.onSelect = this.onSelect.bind(this);
    }

    onSelect() {
        this.props.onSelect(this.props); 
    }

    render() {
        return (
            <div className="fileItem" style={{ width: "100px", height: '150px', float: 'left' }} onClick={this.onSelect}>
                <img src={"http://localhost/content/image/" + this.props.imageUrl} style={divStyle} />
                {this.props.fileName}
                <button className="edit" />
            </div>
        );
    } 
}

export class FileList extends React.Component<any, any> {

    constructor(props : any) {
        super(props);
        this.state = { files: [], skip: 0, take: 10 }
        this.increaseTake = this.increaseTake.bind(this);
        this.onSelect = this.onSelect.bind(this);
    }

    getImages(skip : number, take : number, shouldAdd : boolean) {


        var that = this;
        fetch("http://localhost/admin/shared/file/GetImages?take=" + take + "&skip=" + skip + "&FileType=0&_2331223a3543as", {
            credentials: "same-origin", mode: "no-cors"
        })
            .then(function(response) {
                return response.json();
            })
            .then(function (results) {
                var newFiles = results.data.map((file : any) => ({
                    imageUrl: file.OriginalFileName,
                    fileName: file.DisplayName,
                    fileId: file.FileId,
                    creationDate: file.CreationDate,
                    LCID: file.LCID
                }));

                if (shouldAdd) {
                    newFiles = that.state.files.concat(newFiles);
                }

                that.setState({ files: newFiles });

            });
    }

    onSelect(file : IFileModel) { 
        this.props.onFileSelected(file);
    }

    increaseTake() {
        var currentSkip = this.state.skip + 10;
        this.setState({ skip: currentSkip });
        this.getImages(currentSkip, this.state.take, true);
    }

    componentWillMount() {
        // perfom ajax call
        this.getImages(0, this.state.take, true);
    }


    render() {

        return (<div>

            {this.state.files.map((item: IFileModel, index: number) =>
                <FileItem key={index} {...item} onSelect={this.onSelect} />
                )
            }
            <div style={{ clear: 'both' }}></div>
            <div onClick={this.increaseTake}>take more</div>
        </div>)
    }
}

export class FileGallery extends React.Component <any, any> {
    constructor(props : any) {
        super(props);
        let fm : IFileModel;
        this.state = {
            sidebarCollapsed : false,
            selectedFile : fm
        }; 

        this.onFileSelected = this.onFileSelected.bind(this);
    }

    onFileSelected(file : IFileModel) {
        this.setState({ selectedFile : file }); 
    }

    render() {
        const selectedFile = this.state.selectedFile;
        return (
            <div>
                <div className="FileGalleryHeader">
                    <div>Galley</div>
                    <div>Upload</div>
                </div>
                <div className="FileGalleyMain" style={{ width: "80%", display : 'block', height:"400px", overflow : "auto", float : "left"}}>
                    <FileList onFileSelected={this.onFileSelected}/>
                </div>
                <div style={{ width: "20%", display: "block", float : "right", height: "800px"}}>
                    <DetailsPanel {...selectedFile} onSubmit={(selectedFile) ? selectedFile.onSubmit : null } />
                </div>
        </div>);
    }
}

型号:

export interface IFileModel {
    fileId: number;
    fileName: string;
    categoryId: number;
    fileType: number;
    fileExtension: string;
    fileSize: string;
    width: number;
    height: number;
    creationDate: string;
    imageUrl: string;
    LCID: string;
    onSubmit: Function;
    onSelect: Function; 
}

export interface IFileWrapper {
    file: IFileModel;   
} 

1 个答案:

答案 0 :(得分:0)

就我所查看的代码而言,它可能有两个问题:

1。您在Details

中设置了错误的状态
handleChange(e : any) { 
    console.log(e.target.name, e.target.value);
    this.setState({ [e.target.name] : e.target.value });
}

这应该是:

handleChange(e : any) { 
    console.log(e.target.name, e.target.value);
    this.setState({ currentFile: {
        ...this.state.currentFile,
        [e.target.name]: e.target.value
    });
}

2。您不应将任何props设置为input的值,而应将其设置为state

    const currentFile = this.props;
    return(
        <div style={{border: "1px dashed black", padding: "4px"}}>
            <div>
                <p> File Name: </p>
                <input type="text" value={currentFile.fileName} name="fileName" onChange={this.handleChange} />
            </div>

这应该是:

    const currentFile = this.state;
    return(
        <div style={{border: "1px dashed black", padding: "4px"}}>
            <div>
                <p> File Name: </p>
                <input type="text" value={currentFile.fileName} name="fileName" onChange={this.handleChange} />
            </div>