Asked Nov 17th, 2019 5:50 PM 161 0 3
  • 161 0 3
+1

Hỏi về reactJS - Lấy dữ liệu từ form bằng onChange

Share
  • 161 0 3
import React, {Component} from 'react';
import {connect} from 'react-redux';

class Edit extends Component {
  constructor(props) {
    super(props);
    this.state = {
      fullname: '',
      email: '',
      phonenumber: '',
      birthday: '',
      homeaddress: '',
      registrationdate: '',
      expirydate: '',
      id:''
    }
  }

  //Lấy dữ liệu từ form Edit và gán vào state
  isChange = (event) => {
    
    const name = event.target.name;
    const value = event.target.value;
    this.setState({[name]: value});
  }

  // Lấy giá trị state của store, gán vào state nội bộ của Edit
  UNSAFE_componentWillMount() {
    this.setState({
      id:this.props.editData.key,
      fullname:this.props.editData.fullname,
      email:this.props.editData.email,
      phonenumber:this.props.editData.phonenumber,
      birthday:this.props.editData.birthday,
      homeaddress:this.props.editData.homeaddress,
      registrationdate:this.props.editData.registrationdate,
      expirydate:this.props.editData.expirydate
    })
  }
  
  saveFunction = () => {
    console.log("du lieu editData: " + JSON.stringify(this.props.editData));
    let editObject = {};
    editObject.fullname = this.state.fullname;
    editObject.email = this.state.email;
    editObject.phonenumber = this.state.phonenumber;
    editObject.birthday = this.state.birthday;
    editObject.homeaddress = this.state.homeaddress;
    editObject.registrationdate = this.state.registrationdate;
    editObject.expirydate = this.state.expirydate;
    editObject.id = this.state.id;
    
    this.props.sendEditDataToStore(editObject);
    
  }
  render() {
    
    return (
      <div className="col-6 bg-warning">
        {/* edit case */}
        <h1 className="text-center mb-2">EDIT</h1>
        <div className="form-group row">
          <label htmlFor="fullname" className="col-3 col-form-label">Full Name</label>
          <div className="col-9">
            <input type="text" className="form-control" id="fullname" name="fullname" defaultValue={this.props.editData.fullname} onChange={(event) => this.isChange(event)}/>
          </div>
        </div>
        <div className="form-group row">
          <label htmlFor="email" className="col-3 col-form-label">Email</label>
          <div className="col-9">
            <input type="text" className="form-control" id="email" name="email" defaultValue={this.props.editData.email} onChange={(event) => this.isChange(event)}/>
          </div>
        </div>
        <div className="form-group row">
          <label htmlFor="phonenumber" className="col-3 col-form-label">Phone Number</label>
          <div className="col-9">
            <input type="text" className="form-control" id="phonenumber" name="phonenumber" defaultValue={this.props.editData.phonenumber} onChange={(event) => this.isChange(event)}/>
          </div>
        </div>
        <div className="form-group row">
          <label htmlFor="birthday" className="col-3 col-form-label">Birthday</label>
          <div className="col-9">
            <input type="text" className="form-control" id="birthday" name="birthday" defaultValue={this.props.editData.birthday} onChange={(event) => this.isChange(event)}/>
          </div>
        </div>
        <div className="form-group row">
          <label htmlFor="homeaddress" className="col-3 col-form-label">Home Address</label>
          <div className="col-9">
            <input type="text" className="form-control" id="homeaddress" name="homeaddress" defaultValue={this.props.editData.homeaddress} onChange={(event) => this.isChange(event)}/>
          </div>
        </div>
        <div className="form-group row">
          <label htmlFor="registrationdate" className="col-3 col-form-label">Registration Date</label>
          <div className="col-9">
            <input type="text" className="form-control" id="registrationdate" name="registrationdate" defaultValue={this.props.editData.registrationdate}/>
          </div>
        </div>
        <div className="form-group row">
          <label htmlFor="expirydate" className="col-3 col-form-label">Expiry Date</label>
          <div className="col-9">
            <input type="text" className="form-control" id="expirydate" name="expirydate" defaultValue={this.props.editData.expirydate} onChange={(event) => this.isChange(event)}/>
          </div>
        </div>
        <div className="form-group float-right">
          <button onClick={()=>this.saveFunction()} name="save_edit" type="button" className="btn btn-outline-primary">Save</button>
          <button name="close_edit" type="button" className="btn btn-outline-danger">Close</button>
        </div>
      </div>

    );
  }
}
const mapStateToProps = (state, ownProps) => {
  return {editData: state.editData}
}

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    sendEditDataToStore: (sendEditData) => {   dispatch({type:"GET_EDIT_DATA",sendEditData}) }
  }
}

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

onChange giúp ta lấy dữ liệu từ Form khi có sự THAY ĐỔI - phù hợp cho việc Thêm mới. Tuy nhiên, đối với trường hợp Sửa thì hơi khó tí là khi KHÔNG THAY ĐỔI thì field đó mặc dù có dữ liệu chình ình nhưng nó vẫn không nhận được vào state (ta đã phun ra form từ trước để chuẩn bị sửa). Giờ có giải pháp nào để lúc phun ra form là state nhận được ngay dữ liệu không ạ? Mình cho nó chạy trong UNSAFE_componentWillMount() để gán vào state nội bộ nhưng không hiểu sao nó không chạy được. Hic.

Nguyen Huy Cuong @cuong_nguyen
Nov 18th, 2019 1:06 AM

Value của input thì lấy ở state, nhưng lúc edit lại muốn fill value từ store vào phải ko? sao ko fill thẳng value của input từ store vào, đừng dùng state nữa 😃

0
| Reply
Share

3 ANSWERS


Answered Nov 18th, 2019 2:11 AM
Accepted
+1
  • Ở đây bạn đang lấy dữ liệu từ store nên có thể dẫn đến lần đầu component của bạn render ra form thì phần API dùng để lấy dữ liệu ra edit chưa chạy xong nên bạn chưa có cái phần this.props.editData để dùng được dẫn đến trong hàm componentWillMount() của bạn thì dữ liệu của this.props.editData.key đang là null.
  • Để tránh tình trạng này thì bạn có thể thêm một cái props mới là this.props.isLoading vào. Ở phần gọi API mặc định props này sẽ là true và chuyển về false sau khi API gọi thành công và dữ liệu đã được cập nhật ở reducer.
  • Bên component bạn có thể viết kiểu:
class Edit extends Component {
    ...

    render() {
        this.props.isLoading
        ? <p>Loading dataa...</p>
        : {render phần form của bạn}
    }
}

const mapStateToProps = (state, ownProps) => {
  return {
    editData: state.editData,
    isLoading: state.isLoading,
  }
}

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    sendEditDataToStore: (sendEditData) => {   dispatch({type:"GET_EDIT_DATA",sendEditData}) }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Edit);
Share
Dũng @quocdungabc
Nov 18th, 2019 4:41 AM

Mình đọc nãy giờ mà chưa hiểu lắm. File store của mình thế này, giờ sửa lại như nào bạn.

//ĐÂY LÀ FILE store.js
import * as firebase from 'firebase';
import {gymData} from './firebaseConnect';
//Khai báo biến redux
let redux = require('redux');

//Khai báo reducer
const allReducerInitialState = {
  editData:{},
}
const allReducer = (state = allReducerInitialState, action) => {
  switch (action.type) {
    case "ADD_DATA":
      let ketnoi1 = firebase.database().ref('dataForGym');
      ketnoi1.push(action.customer);
      console.log("Thêm dữ liệu thành công!");
      return state

    case "GET_DATA"://Lấy dữ liệu đưa qua store khi bấm vào nút Edit
      return {...state,editData:action.getOneRow}

    case "GET_EDIT_DATA"://Lấy dữ liệu ĐÃ SỬA đưa qua store và update lên firebase
      let ketnoi2 = firebase.database().ref('dataForGym');
      ketnoi2.child(action.sendEditData.id).update({
        fullname:action.sendEditData.fullname,
        email:action.sendEditData.email,
        phonenumber:action.sendEditData.phonenumber,
        birthday:action.sendEditData.birthday,
        homeaddress:action.sendEditData.homeaddress,
        registrationdate:action.sendEditData.registrationdate,
        expirydate:action.sendEditData.expirydate
      })
      console.log("Cap nhat thanh cong!");
      return {...state,editData:{}} //update xong thì gán về rỗng

    default:
      return state
  }
}

//Khai báo store
let store = redux.createStore(allReducer);

//theo dõi state của store, thay đổi thì in ra màn hình
store.subscribe(function(){
  console.log(JSON.stringify(store.getState()));
})

export default store;

0
| Reply
Share
Dũng @quocdungabc
Nov 18th, 2019 1:38 PM

Nhờ gợi ý của bạn mình làm được rồi. Đó là phải tìm cách render lại form mỗi lần click vào nút (ban đầu cho form ẩn đi, sau khi có tương tác dữ liệu thì mới lòi nó ra, hơi củ chuối tí nhưng it worked)

0
| Reply
Share
Nov 18th, 2019 5:06 PM

@quocdungabc chính xác rồi đó bạn. Sorry bạn mình bận việc nên không để ý giờ mới check được comment của bạn

0
| Reply
Share
Dũng @quocdungabc
Nov 19th, 2019 5:55 AM
0
| Reply
Share
Answered Nov 18th, 2019 12:52 AM
+3
<div className="col-9">
     <input type="text" className="form-control" id="fullname" name="fullname" defaultValue={this.props.editData.fullname} onChange={(event) => this.isChange(event)}/>
</div>

chỗ defaultValue bạn đặt bằng giá trị của state thì sao nhỉ?

Share
Dũng @quocdungabc
Nov 18th, 2019 4:36 AM

state này mình lấy bên store nên chỉ readonly thôi, còn muốn update thì phải tìm cách gán vào state nội bộ của form Edit chứ, rồi từ đó ta gửi ngược lại qua store để cập nhật vào csdl. Theo kiến thức của mình biết là vậy. Hi. 😃

+1
| Reply
Share
Bùi Hiếu @buihieubthc2rb
Nov 18th, 2019 5:57 AM

@quocdungabc

//Lấy dữ liệu từ form Edit và gán vào state
  isChange = (event) => {
    
    const name = event.target.name;
    const value = event.target.value;
    this.setState({[name]: value});
  }

Nhưng mà ở hàm onChange này thì bạn mới chỉ làm thay đổi state nội bộ, chưa thấy có gọi đến action thay đổi store. Còn ở render thì bạn vẫn dùng prop (lấy từ store). Có vẻ là vấn đề ở đây.

0
| Reply
Share
Dũng @quocdungabc
Nov 18th, 2019 6:39 AM

@buihieubthc2rb ah action của mình nè:

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    sendEditDataToStore: (sendEditData) => {   dispatch({type:"GET_EDIT_DATA",sendEditData}) }
  }
}

Lúc này mới gửi qua store, mà mình bị kẹt ở bước lấy nên chưa gửi qua được. (Phải bấm nút Save thì action này mới thực thi)

+1
| Reply
Share
Bùi Hiếu @buihieubthc2rb
Nov 18th, 2019 7:06 AM

@quocdungabc có vẻ là mình cũng chưa hiểu code trên nhiều nên không thể giúp bạn giải quyết 🙇

0
| Reply
Share
Dũng @quocdungabc
Nov 18th, 2019 7:20 AM

@buihieubthc2rb : uh, bạn dành thời gian ra xem giúp là mình cũng trân trọng rồi. Cảm ơn bạn hiền nhe.

+1
| Reply
Share
Answered Nov 18th, 2019 2:32 AM
0
  • hàm UNSAFE_componentWillMount() thì giờ không nên dùng nữa tại vì từ bản React 17 sẽ không được support nữa thay vào đó bạn có thể dùng hàm componentDidMount()
  • bạn đã đổ dữ liệu vào state rồi thì không cần thiết phải dùng defaultValue={this.props.editData.registrationdate} thay vào đó dùng defaultValue={this.state.registrationdate}
  • trong code thì mình cũng chưa thấy có action nào để gọi lấy dữ liệu từ backend về thế nên trong store của bạn sẽ bị null Bạn thử thay các thứ trên vào xem sao!
Share
Dũng @quocdungabc
Nov 18th, 2019 4:40 AM
  • Mình muốn chạy trước khi render để có dữ liệu thì dùng DiDMount bị muộn rồi ạ.
  • state đó mình lấy bên store (editData) rồi phun ra form luôn chứ chưa đổ vào state nội bộ của form Edit được, hic. Đang vướng chỗ này.
  • Uhm, mình xài csdl firebase. Cảm ơn pác nhe.
0
| Reply
Share