【问题标题】:Updating local state after component has rendered组件渲染后更新本地状态
【发布时间】:2019-10-28 15:13:46
【问题描述】:

我正在使用 React、Redux 和 Firebase 创建一个项目规划应用。我的 Firestore 数据库中的单个项目记录包含一个 Title 和一些 Content。当我去更新一个项目时,我将输入字段的 defaultValues 设置为我想要编辑的项目的正确数据。但是,仅当我对 both 内容和标题输入字段进行更改时,更新才有效。否则,在提交这些值时,数据将被删除,因为本地状态没有看到任何变化,因此将未触及的字段更新为空字符串:""

我曾尝试在 render 方法中设置 EditProject 组件的本地状态,但这是不可能的:

render() {
    const { project, auth } = this.props;
    if (!auth.uid) return <Redirect to="/signin" />;
    if (project) {
      this.setState({
        title: project.title,
        content: project.content
      });

...

我也尝试过在componentDidMount 期间设置状态,如下所示:

  componentDidMount = () =>{
    const { project } = this.props;
    this.setState({
      title: project.title,
      content: project.content
    })
  }

但是这个问题是mapStateToProps在componentDidMount之前没有映射项目属性

最后,我尝试从父组件传递项目道具,即projectDetails,但我无法成功这样做。我可能在这部分做错了,所以请让我知道是否有使用我拥有的代码的好方法。在ProjectDetails:

<Link to={"/edit/" + docId} key={docId}>
  <button className="btn pink lighten-1 z-depth-0">Edit</button>
</Link>

这链接到我正在尝试修复的“损坏”的 EditDetails 组件。


这是我的 EditProject 组件代码

class EditProject extends Component {
  state = {
    title: "",
    content: ""
  };

  handleChange = e => {
    this.setState({
      [e.target.id]: e.target.value
    });
  };

  handleSubmit = e => {
    e.preventDefault();
    let localProject = this.state;
    let docId = this.props.docId;
    this.props.editProject(localProject, docId);
    const projectDetailURL = "/project/" + docId;
    this.props.history.push(projectDetailURL);
  };

  render() {
    const { project, auth } = this.props;
    if (!auth.uid) return <Redirect to="/signin" />;
    if (project) {
      return (
        <div className="container section project-details">
          <div className="card z-depth-0">
            <div className="card-content">
              <form onSubmit={this.handleSubmit} className="white">
                <h5 className="grey-text text-darken-3">Edit Project</h5>
                <div className="input-field">
                  <label htmlFor="title" className="active">
                    Title
                  </label>
                  <input
                    onChange={this.handleChange}
                    type="text"
                    id="title"
                    defaultValue={project.title}
                  />
                </div>
                <div className="input-field">
                  <label htmlFor="content" className="active">
                    Edit Project Content
                  </label>
                  <textarea
                    id="content"
                    onChange={this.handleChange}
                    className="materialize-textarea"
                    defaultValue={project.content}
                  />
                </div>
                <div className="input-field">
                  <button className="btn pink lighten-1 z-depth-0">
                    Update
                  </button>
                </div>
              </form>
            </div>
            <div className="card-action grey lighten-4 grey-text">
              <div>
                Posted by {project.authorFirstName} {project.authorLastName}
              </div>
              <div>{moment(project.createdAt.toDate()).calendar()}</div>
              <div className="right-align" />
            </div>
          </div>
        </div>
      );
    } else {
      return (
        <div className="container center">
          <p>Loading project...</p>
        </div>
      );
    }
  }
}

const mapStateToProps = (state, ownProps) => {
  //id = the document id of the project
  const id = ownProps.match.params.id;
  const projects = state.firestore.data.projects;
  const project = projects ? projects[id] : null;
  return {
    project: project,
    auth: state.firebase.auth,
    docId: id
  };
};

const mapDispatchToProps = dispatch => {
  return {
    editProject: (project, docId) => dispatch(editProject(project, docId))
  };
};

export default compose(
  connect(
    mapStateToProps,
    mapDispatchToProps
  ),
  firestoreConnect([
    {
      collection: "projects"
    }
  ])
)(EditProject);

访问编辑页面时,如果用户未对输入字段进行任何更改,我希望数据保持不变。

【问题讨论】:

  • 控制台记录 props.project 、 props.projects 和 props.id 时的输出是什么。在组件中确实安装了。
  • 因为 mapStateToProps 在 componentDidMount 之后完成,它会记录 undefined
  • 所有这些都给你 undefined ?
  • @Muljayan 在 componentDidMount 中,是的,它只返回未定义的。一旦渲染方法运行,我就可以看到我的组件的所有道具(包括包含Title 和Content 的项目道具我需要更新本地状态)。
  • 你可以试试console.log(this.props.projects) 在组件中确实挂载了。输出是什么?

标签: reactjs firebase redux


【解决方案1】:

我能够通过使用 React Router 将 props 从其“父组件”传递给我的 EditProject 组件来正确更新我的本地状态。我使用 React 路由器来执行此操作,因为 EditProject 组件实际上并未嵌套在此“父组件”中。

以下是使用 React Router 将 props 传递给其他组件的方法:

指定您要发送道具的位置以及要发送的内容:

//ProjectDetails Component

<Link to={{
            pathname: "/edit/" + docId,
            state: {
              title: project.title,
              content: project.content
            }
            }}>
   <button className="btn">Edit</button>
</Link>


在componentDidMount()生命周期方法中获取props,并使用setState()更新本地状态。

//EditProject Component (component recieving props from ProjectDetails)

class EditProject extends Component {
  state = {
    title: "",
    content: ""
  };

  componentDidMount = () => {
    //Aquire proprs from React Router
    const title = this.props.location.state.title
    const content = this.props.location.state.content

    //Update the local state
    this.setState({
      title: title,
      content: content
    })
  }

我希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 2022-06-30
    • 2019-06-17
    • 2018-04-20
    • 2019-02-18
    • 2021-05-19
    • 2019-10-11
    • 2022-01-26
    • 2021-01-27
    • 2019-06-29
    相关资源
    最近更新 更多