首页 > 解决方案 > 使用 this.handleChange 和 Axios 反应表单表现得很奇怪

问题描述

解决了

我有一个 React/Typescript 应用程序,它有一个我在网站中使用的表单,它呈现我们从 Mongo 数据库中看到的电影。我进行了设置,以便我们可以通过编辑表单编辑数据库中的一部电影。一切都很顺利,但第一个字段是电影标题。每当我更改该字段时,它会立即阻止我做任何其他事情,我必须再次单击该字段。

IE初始标题:“Foo”->“Fo”->单击->“F”->单击->“”->单击->“B”->单击->“Ba”->单击->“Bar” ”。

中的所有其他字段都没有此行为。据我所知,所有输入表单都是相同的(类型:文本),应该没有任何区别。我可以在任何其他输入字段中不间断地输入完整的句子,但无论我做什么,第一个都不允许我这样做。为什么?

const EditBody = styled.div`{blablabla}`;

export interface Props {
    match: {
        params: {
            title: string
        }
    },
    history: any
}

type MovieObject = {
    comments: string,
    imdb: string,
    mtc: string,
    rtc: string,
    smn: string,
    title: string
}

class Edit extends Component<Props, { movie: any }> {
    constructor(props: any) {
        super(props);

        this.state = {
            movie: [
                {
                    comments: '',
                    imdb: '',
                    mtc: '',
                    rtc: '',
                    smn: '',
                    title: '',
                    pictureUrl: '',
                    __v: Number,
                    _id: String
                }]
        };

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

    componentDidMount() {
        this.callServerForDatabase()
            .then(data => this.setState({ movie: data }))
            .catch(err => console.log(err));
    };

    callServerForDatabase = async () => {
        const { match: { params } } = this.props;

        const response = await fetch(`/edit/${params.title}`);
        const body = await response.json();

        if (response.status !== 200) throw Error(body.message);
        return body;
    };

    handleChange(e: any) {
        e.preventDefault();

        const name = e.target.name;
        const value = e.target.value;

        let thisStateMovieClone: MovieObject[] = [...this.state.movie];

        let updatedMovieObj: MovieObject = {
            ...thisStateMovieClone[0],
            [name]: value
        }

        thisStateMovieClone[0] = updatedMovieObj;

        this.setState({
            movie: thisStateMovieClone
        })
    }


    handleUpdate = (e: any) => {
        e.preventDefault();

        axios.post(`/edit/${this.state.movie.title}`, this.state.movie)
        .then(() => this.props.history.push("/database"));
    };

    handleDelete = (e: any) => {
        e.preventDefault();

        axios.post('/delete', this.state.movie)
        .then(() => this.props.history.push("/database"));
    };

    render() {
        return (
            <EditBody>
                <h2>Update Movie Data</h2>


                {this.state.movie.map((movie: any) =>
                    <div key={movie.title} className="container">
                        <form action={`/edit/${movie.title}?_method=PUT`} method="PUT">

                            <div className="inputrow">
                                <p className="description">Movie Title
                                    <input className="input" type="text" value={movie.title} onChange={this.handleChange} name="title" /></p></div>

                            <div className="inputrow">
                                <p className="description">Rotten Tomatoes Score
                                <input className="input" type="text" value={movie.rtc} onChange={this.handleChange} name="rtc" /></p></div>

                            <div className="inputrow">
                                <p className="description">Metacritic Score
                                <input className="input" type="text" value={movie.mtc} onChange={this.handleChange} name="mtc" /></p></div>

                            <div className="inputrow">
                                <p className="description">IMDB Score
                                <input className="input" type="text" value={movie.imdb} onChange={this.handleChange} name="imdb" /></p></div>

                            <div className="inputrow">
                                <p className="description">Scary Movie Night Score
                                <input className="input" type="text" value={movie.smn} onChange={this.handleChange} name="smn" /></p></div>

                            <div className="inputrow">
                                <p className="description">Comments
                                <input className="input" type="text" value={movie.comments} onChange={this.handleChange} name="comments" /></p></div>


                            <button id="submitButton" type="submit" onClick={this.handleUpdate}><h2>Update Movie</h2></button> or <button id="submitButton" type="submit" onClick={this.handleDelete}><h2>Delete Movie</h2></button>

                        </form>
                    </div>
                )}
            </EditBody>
        )
    }
};

最重要的是,我对服务器的 axios 请求有问题。它可以工作(即电影被更新或从数据库中删除),但this.props.history.push要么不工作(现在),要么当它工作时,它比服务器响应更快,所以它重新路由回没有'的 /database 页面t 还没有收到更新的信息。只有在刷新后 /database 才会显示正确的信息。我已经尝试过 async/await、setTimeout、this.props.context.push,并且在返回的 promise 之后看到了 .then()。没有任何效果。我认为是因为 this.history 推送到页面的旧版本,而不是实际再次加载页面?

这两个问题都快把我逼疯了!任何帮助,将不胜感激。如果有人需要查看更多代码,请告诉我。

编辑:

componentDidMount() 和 callServer.. 函数是因为我们通过单击要编辑的电影进入此 /edit 页面。因此,在我在另一个页面上单击它后,它会从服务器获取该电影的信息。

标签: reactjsmongodbtypescriptforms

解决方案


对于任何阅读的人:这是因为我将{movie.title}也作为容器 div 的键。这意味着它每次都重新渲染 div,因为键也发生了变化。我创建了一个索引参数并将键分配给解决渲染问题的键。现在只剩下axios问题了..

{this.state.movie.map((movie: any, index: any) =>
                    <div key={index} className="container"> //CHANGED KEY VALUE
                        <form action={`/edit/${movie.title}?_method=PUT`} method="PUT">

// WHICH COLLIDED WITH THIS VALUE
                            <div className="inputrow">
                                <p className="description">Movie Title
                                    <input className="input" type="text" value={movie.title} onChange={this.handleChange} name="title" /></p></div> 

推荐阅读