如何替换componentWillRecieveProps

时间:2018-10-19 03:52:19

标签: reactjs redux

我是redux的新手,并按照this tutorial创建了一个带有react和redux的简单博客应用程序。我已经完成了,但是我注意到componentWillRecievePropsbeing deprecated。我正在尝试用更多最新代码替换它,但一直无法理解该怎么做。我已经读过this article的有关将'componentWillReceiveProps'替换为'getDerivedStateFromProps'的知识,但我认为这不是React's blog post正确使用getDerivedStateFromProps的方法,因为用另一种描述替换了其中的一种。

我当前的componentWillRecieveProps代码:

import axios from "axios";
import React from "react";
import { connect } from "react-redux";

class Form extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            title: "",
            body: "",
            author: ""
        };

        this.handleChangeField = this.handleChangeField.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    //This is deprecated
    componentWillReceiveProps(nextProps) {
        console.log(this);
        if (nextProps.articleToEdit) {
            this.setState({
                title: nextProps.articleToEdit.title,
                body: nextProps.articleToEdit.body,
                author: nextProps.articleToEdit.author
            });
        }
    }


    handleSubmit() {
        const { onSubmit, articleToEdit, onEdit } = this.props;
        const { title, body, author } = this.state;

        if (!articleToEdit) {
            return axios
                .post("http://localhost:8000/api/articles", {
                    title,
                    body,
                    author
                })
                .then(res => onSubmit(res.data))
                .then(() => this.setState({ title: "", body: "", author: "" }));
        } else {
            return axios
                .patch(
                    `http://localhost:8000/api/articles/${articleToEdit._id}`,
                    {
                        title,
                        body,
                        author
                    }
                )
                .then(res => onEdit(res.data))
                .then(() => this.setState({ title: "", body: "", author: "" }));
        }
    }

    handleChangeField(key, event) {
        this.setState({
            [key]: event.target.value
        });
    }

    render() {
        const { articleToEdit } = this.props;
        const { title, body, author } = this.state;

        return (
            <div className="col-12 col-lg-6 offset-lg-3">
                <input
                    onChange={ev => this.handleChangeField("title", ev)}
                    value={title}
                    className="form-control my-3"
                    placeholder="Article Title"
                />
                <textarea
                    onChange={ev => this.handleChangeField("body", ev)}
                    className="form-control my-3"
                    placeholder="Article Body"
                    value={body}
                />
                <input
                    onChange={ev => this.handleChangeField("author", ev)}
                    value={author}
                    className="form-control my-3"
                    placeholder="Article Author"
                />
                <button
                    onClick={this.handleSubmit}
                    className="btn btn-primary float-right"
                >
                    {articleToEdit ? "Update" : "Submit"}
                </button>
            </div>
        );
    }
}

const mapDispatchToProps = dispatch => ({
    onSubmit: data => dispatch({ type: "SUBMIT_ARTICLE", data }),
    onEdit: data => dispatch({ type: "EDIT_ARTICLE", data })
});

const mapStateToProps = state => ({
    articleToEdit: state.home.articleToEdit
});

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(Form);

Full Repo Codesandbox

如果不赞成使用componentWillRecieveProps,应该如何更新我的代码?

编辑:使用getDerivedStateFromProps,nextProps仍然具有先前的值,因此在返回对象时,状态会重新设置为先前的状态,实际上不会进行任何更新。

在这种情况下,尝试使用prevState值不起作用,因为初始prevState值都是空字符串,在组件呈现时会被调用并置于状态,这在初始页面加载时以及单击“编辑”按钮时发生。

    static getDerivedStateFromProps(nextProps, prevState) {
    if (
        JSON.stringify(nextProps.articleToEdit) !==
        JSON.stringify(prevState.articleToEdit)
    ) {
        console.log(nextProps);
        console.log(prevState);
        return {
            title: nextProps.articleToEdit.title,
            body: nextProps.articleToEdit.body,
            author: nextProps.articleToEdit.author
        }; // <- is this actually equivalent to this.setState()?
    } else {
        return null;
    }
}

3 个答案:

答案 0 :(得分:3)

通过引入一种称为getDerivedStateFromProps()的新生命周期方法,不推荐使用

componentWillReceiveProps()方法。

请记住,您应该始终将当前的道具与如下所示的以​​前的道具进行比较,如果两者都不相同,则请执行setState,否则会陷入无限的setState警告

在下面的代码处代替componentWillReceiveProps方法

   static getDerivedStateFromProps(nextProps,  prevState)  {
          //Below I used JSON.stringify to compare current props with previous props of articleToEdit object
          if (JSON.stringify(nextProps.articleToEdit) !== JSON.stringify(prevState.artileToEdit)){
        return({
            title: nextProps.articleToEdit.title,
            body: nextProps.articleToEdit.body,
            author: nextProps.articleToEdit.author
        });// <- this is setState equivalent
       }
       return null;
   }

编辑:

您无法在getDerivedStateFromProps函数中访问this.props。如果您想访问函数内部的某些先前道具(例如用于比较),则可以在状态内镜像此类值。然后,您可以将nextProps与上面状态存储的值进行比较

检查此线程以更好地了解

https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#updating-state-based-on-props

答案 1 :(得分:1)

我的建议是,注意警告,因为使用不当,React会通过替换此生命周期方法来给我们-他们告诉我们仅在确实需要时才这样做,因为可能有更好的方法< / em>(包括较新的getDerivedStateFromProps)。

根据我在这段代码中收集到的信息,您正在呈现一个表单,让用户与它进行交互,但是在某些情况下,您用props(覆盖组件状态)替换了用户的输入。很容易看出为什么这是一种反模式,但是在不了解有关该应用程序的更多信息的情况下很难重新构造。

我建议将输入的值移到父状态(或创建一个新父级),然后更改为value={props.title}等。如果在任何情况下都有一个控制表单状态的父级,则您最好一直保持表格状态。

答案 2 :(得分:1)

好的。这是您的应用程序的有效示例。我完全重写了它的结构,以使每个组件都能处理自己的状态和道具集。这些组件还可以重复使用,因此可以放置在任何地方-只要它需要道具即可。

注意:

  1. 请勿混用.jsx.js(有关修复,请参见步骤6)
  2. 分隔container-components from your components。还使可重用组件成为可能-大大简化了状态和属性逻辑。
  3. 对于您的应用程序,您可以完全删除redux,而是让您的服务器成为“真理之源”。因此,您无需保存到redux状态和操作redux状态,而只需发出AJAX请求以利用APICRUDarticles(例如,表单提交会向post发送API请求,这将向数据库添加文章,然后将用户重定向回/articles,或者可以在发布并更新{{ 1}}状态(包含新数据)。由您自己决定如何处理。但是,如此说来,您真正需要做的唯一事情是,如果您要共享来自两个单独的大量嵌套组件的道具。
  4. 如果使用redux,请添加一个ShowArticlestypes文件夹,如下例所示。它使您的代码更易于阅读和模块化。
  5. 除非根文件夹仅包含一个文件,否则请避免使用actions。否则,当应用程序崩溃(并且将会崩溃)时,如果您发现有很多“ index.js”崩溃,将很麻烦。
  6. 您正在使用的样板很旧,使用它使您的生活更加艰难。我创建了一个MERN Fullstack Boilerplate,它允许执行以下操作:类方法中的胖箭头函数,scss / css node_module导入,组件级scss模块导入,同时运行index.jsserver,具有错误覆盖,拖累等等。我强烈建议您将现有的内容移植到它上。

工作示例:https://codesandbox.io/s/4x4kxn9qxw(不幸的是,client模板不允许导入create-react-app模块...哦,您会明白的)