ใช้ state หรือ refs ใน React.js form components?


116

ฉันเริ่มต้นด้วย React.js และฉันต้องการทำแบบฟอร์มง่ายๆ แต่ในเอกสารฉันพบสองวิธีในการทำ

อันแรกใช้Refs :

var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var author = React.findDOMNode(this.refs.author).value.trim();
    var text = React.findDOMNode(this.refs.text).value.trim();
    if (!text || !author) {
      return;
    }
    // TODO: send request to the server
    React.findDOMNode(this.refs.author).value = '';
    React.findDOMNode(this.refs.text).value = '';
    return;
  },
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

และอันที่สองกำลังใช้stateภายในองค์ประกอบ React:

var TodoTextInput = React.createClass({
  getInitialState: function() {
    return {
      value: this.props.value || ''
    };
  },

  render: function() /*object*/ {
    return (
      <input className={this.props.className}
      id={this.props.id}
      placeholder={this.props.placeholder}
      onBlur={this._save}
      value={this.state.value}
      />
    );
  },

  _save: function() {
    this.props.onSave(this.state.value);
    this.setState({value: ''
  });
});

ฉันมองไม่เห็นข้อดีข้อเสียของทางเลือกทั้งสองถ้ามีอยู่ ขอบคุณ


ฉันขาดอะไรที่นี่? ทำไมคุณไม่ใช้วัตถุเหตุการณ์เพื่อรับค่าฟอร์ม นั่นดูเหมือนจะเป็นเหตุผลเดียวที่ต้องใช้แบบฟอร์มที่นี่ตั้งแต่แรก หากคุณไม่ได้ใช้พฤติกรรมการส่งเริ่มต้นและมีการอ้างอิงเกี่ยวกับอินพุตคุณไม่จำเป็นต้องรวมไว้ในแบบฟอร์ม
NectarSoft

คำตอบ:


143

เวอร์ชันสั้น: หลีกเลี่ยงการอ้างอิง


พวกเขาไม่ดีต่อการบำรุงรักษาและสูญเสียความเรียบง่ายของการแสดงผลแบบจำลอง WYSIWYG ไปมาก

คุณมีแบบฟอร์ม คุณต้องเพิ่มปุ่มที่รีเซ็ตแบบฟอร์ม

  • refs:
    • จัดการ DOM
    • การเรนเดอร์อธิบายลักษณะของฟอร์มเมื่อ 3 นาทีที่แล้ว
  • สถานะ
    • setState
    • การแสดงผลอธิบายว่าฟอร์มมีลักษณะอย่างไร

คุณมีฟิลด์หมายเลข CCV ในอินพุตและฟิลด์อื่น ๆ ในแอปพลิเคชันของคุณที่เป็นตัวเลข ตอนนี้คุณต้องบังคับให้ผู้ใช้ป้อนตัวเลขเท่านั้น

  • refs:
    • เพิ่มตัวจัดการ onChange (เราไม่ได้ใช้การอ้างอิงเพื่อหลีกเลี่ยงสิ่งนี้หรือไม่)
    • จัดการ dom ใน onChange หากไม่ใช่ตัวเลข
  • สถานะ
    • คุณมีตัวจัดการ onChange อยู่แล้ว
    • เพิ่มคำสั่ง if หากไม่ถูกต้องไม่ต้องทำอะไรเลย
    • การเรนเดอร์จะถูกเรียกก็ต่อเมื่อมันจะให้ผลลัพธ์ที่แตกต่างกัน

เอ๊ะไม่เป็นไรนายกรัฐมนตรีต้องการให้เราทำเงากล่องสีแดงถ้ามันไม่ถูกต้อง

  • refs:
    • ทำให้ onChange handler เพียงแค่เรียก ForceUpdate หรืออะไร?
    • สร้างการแสดงผลตาม ... ฮะ?
    • เราจะเอาค่าไปตรวจสอบความถูกต้องในการเรนเดอร์ได้ที่ไหน
    • จัดการคุณสมบัติ className ขององค์ประกอบด้วยตนเองหรือไม่
    • ฉันหลงทาง
    • เขียนใหม่โดยไม่ต้องอ้างอิง?
    • อ่านจาก dom ในการเรนเดอร์ถ้าเราติดตั้งไว้เป็นอย่างอื่นถือว่าถูกต้อง?
  • สถานะ:
    • ลบคำสั่ง if
    • ทำการ render validate ตาม this.state

เราจำเป็นต้องให้การควบคุมกลับไปที่ผู้ปกครอง ขณะนี้ข้อมูลอยู่ในอุปกรณ์ประกอบฉากและเราจำเป็นต้องตอบสนองต่อการเปลี่ยนแปลง

  • refs:
    • ใช้ componentDidMount, componentWillUpdate และ componentDidUpdate
    • เปลี่ยนอุปกรณ์ประกอบฉากก่อนหน้าด้วยตนเอง
    • จัดการ Dom ด้วยชุดการเปลี่ยนแปลงที่น้อยที่สุด
    • เฮ้! เรากำลังใช้ react ในการตอบสนอง ...
    • ยังมีอีก แต่นิ้วของฉันเจ็บ
  • สถานะ:
    • sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js

ผู้คนคิดว่าการอ้างอิงนั้น 'ง่ายกว่า' มากกว่าการทำให้อยู่ในสถานะ สิ่งนี้อาจเป็นจริงในช่วง 20 นาทีแรกซึ่งไม่เป็นความจริงในประสบการณ์ของฉันหลังจากนั้น แสดงจุดยืนของตัวเองว่า "ใช่ฉันจะทำให้เสร็จใน 5 นาที" แทนที่จะเป็น "แน่นอนฉันจะเขียนส่วนประกอบบางอย่างใหม่"


3
คุณช่วยอธิบายเพิ่มเติมเกี่ยวกับ sed -e 's / this.state / this.props /' 's / handleChange / onChange /' -i form.js ได้ไหม
gabrielgiussi

1
ไม่ฉันหมายถึงการเปลี่ยนแปลงที่แท้จริงของโดม React.findDOMNode(this.refs.foo). ถ้าคุณเปลี่ยนเช่นthis.refs.foo.props.barจะไม่มีอะไรเกิดขึ้น
Brigand

1
เช่นหากคุณ <input onChange={this.handleChange} value={this.state.foo} />เปลี่ยนเป็น<input onChange={this.props.handleChange} value={this.props.foo} />หรือแก้ไขฟังก์ชัน handleChange ของคุณเพื่อเรียกการเรียกกลับในอุปกรณ์ประกอบฉาก ไม่ว่าจะด้วยวิธีใดการเปลี่ยนแปลงเล็ก ๆ น้อย ๆ ที่ชัดเจน
Brigand

4
ไม่แน่ใจว่าฉันคนเดียวที่หาคำตอบของคุณสับสนเล็กน้อย คุณช่วยแสดงตัวอย่างโค้ดที่ทำให้ประเด็นของคุณชัดเจนขึ้นได้ไหม
Rishabh

2
การมีอินพุตมากกว่า 50 รายการบนหน้าจอการแสดงผลแต่ละครั้งเมื่อมีการเปลี่ยนแปลงสถานะเป็นสิ่งที่ไม่พึงปรารถนา การจัดองค์ประกอบแต่ละinputฟิลด์โดยที่แต่ละฟิลด์คงสถานะของตัวเองนั้นเหมาะอย่างยิ่ง เมื่อถึงจุดหนึ่งเราจำเป็นต้องกระทบยอดรัฐอิสระต่างๆเหล่านี้กับแบบจำลองที่ใหญ่กว่า บางทีเราอาจมีการบันทึกอัตโนมัติในตัวจับเวลาหรือเราแค่ประหยัดcomponentWillUnmountนี่คือที่ที่ฉันคิดว่าrefsเหมาะที่สุดในระหว่างการปรับใหม่เราดึงstateค่าจากแต่ละค่าออกมาrefและไม่มีใครฉลาดกว่า ฉันเห็นด้วยในกรณีส่วนใหญ่stateคือคำตอบ แต่ด้วยจำนวนมากการinputsใช้refsรูปแบบที่เหมาะสมเป็นประโยชน์ต่อประสิทธิภาพ
ลักซ์

105

ฉันเคยเห็นคนสองสามคนอ้างคำตอบข้างต้นว่าเป็นเหตุผลว่า "ไม่เคยใช้การอ้างอิง" และฉันต้องการแสดงความคิดเห็น (รวมถึง React devs อื่น ๆ ที่ฉันเคยพูดถึง)

ความรู้สึก "ไม่ใช้การอ้างอิง" นั้นถูกต้องเมื่อพูดถึงการใช้มันสำหรับอินสแตนซ์คอมโพเนนต์ หมายความว่าคุณไม่ควรใช้การอ้างอิงเป็นวิธีในการดึงอินสแตนซ์ของคอมโพเนนต์และวิธีการเรียกใช้ นี่เป็นวิธีที่ไม่ถูกต้องในการใช้ refs และเมื่อ refs ไปทางทิศใต้อย่างรวดเร็ว

วิธีที่ถูกต้อง (และมีประโยชน์มาก) ในการใช้การอ้างอิงคือเมื่อคุณใช้เพื่อรับค่าบางอย่างจาก DOM ตัวอย่างเช่นหากคุณมีช่องป้อนข้อมูลที่แนบ ref กับอินพุตนั้นการจับค่าในภายหลังผ่านการอ้างอิงก็ใช้ได้ หากไม่มีวิธีนี้คุณจะต้องดำเนินการตามขั้นตอนที่กำหนดไว้อย่างเป็นธรรมเพื่อให้ช่องป้อนข้อมูลของคุณเป็นข้อมูลล่าสุดไม่ว่าจะเป็นรัฐในพื้นที่หรือร้านค้าฟลักซ์ของคุณซึ่งดูเหมือนจะไม่จำเป็น

2019 แก้ไข: สวัสดีเพื่อนในอนาคต นอกเหนือจากสิ่งที่ฉันพูดถึงเมื่อสองสามปีก่อน ^ ด้วย React Hooks การอ้างอิงยังเป็นวิธีที่ยอดเยี่ยมในการติดตามข้อมูลระหว่างการแสดงผลและไม่ จำกัด เพียงแค่การจับโหนด DOM


3
ย่อหน้าสุดท้ายของคุณมีเหตุผล แต่คุณสามารถอธิบายย่อหน้าที่สองของคุณได้หรือไม่? อะไรคือตัวอย่างที่เป็นรูปธรรมของการคว้าอินสแตนซ์คอมโพเนนต์และเรียกวิธีการที่ถือว่าไม่ถูกต้อง
Danny Libin

2
ฉันเห็นด้วยกับสิ่งนี้ ฉันใช้การอ้างอิงเว้นแต่ / จนกว่าฉันจะต้องทำการตรวจสอบความถูกต้องหรือจัดการค่าของฟิลด์ ถ้าฉันต้องการตรวจสอบความถูกต้องเกี่ยวกับการเปลี่ยนแปลงหรือเปลี่ยนค่าโดยทางโปรแกรมฉันจะใช้ state
Christopher Davies

1
ฉันเห็นด้วยกับเรื่องนี้เช่นกัน ในระหว่างขั้นตอนการค้นพบฉันตั้งใจเข้าหาหน้าจอที่มีอินพุตจำนวนมากที่ไร้เดียงสา ค่าอินพุตทั้งหมดที่จัดเก็บในแผนที่ (ในสถานะ) คีย์โดย id ไม่จำเป็นต้องบอกว่าประสิทธิภาพได้รับผลกระทบตั้งแต่การตั้งค่าสถานะและการแสดงผลอินพุต 50+ (วัสดุ -Ui บางตัวซึ่งมีน้ำหนักมาก!) ในการเปลี่ยนแปลง UI เล็กน้อยเช่นการคลิกช่องทำเครื่องหมายไม่เหมาะ การจัดองค์ประกอบแต่ละอินพุตที่สามารถรักษาสถานะของตัวเองดูเหมือนจะเป็นแนวทางที่เหมาะสม หากจำเป็นต้องมีการกระทบยอดเพียงแค่ดูrefsและรับค่าสถานะ ดูเหมือนว่าเป็นรูปแบบที่ดีจริงๆ
ลักซ์

2
ฉันเห็นด้วยอย่างยิ่ง คำตอบที่ยอมรับนั้นคลุมเครือเกินไปในความคิดของฉัน
James Wright

ฉันเห็นด้วย. ในขณะที่ออกแบบส่วนประกอบฟอร์มทั่วไปสิ่งนี้ทำให้จุดเจ็บปวดของส่วนประกอบที่ควบคุมและการจัดการโฟกัสการจัดการข้อผิดพลาด ฯลฯ เป็นไปไม่ได้ที่จะมีสถาปัตยกรรมที่สะอาดในความเป็นจริง คุยกับฉันถ้าจำเป็น ฉันกำลังย้ายส่วนประกอบไปยังการอ้างอิง
kushalvm

6

TL; DRพูดโดยทั่วไปrefsขัดกับปรัชญาการประกาศของ React ดังนั้นคุณควรใช้เป็นทางเลือกสุดท้าย ใช้state / propsทุกครั้งที่ทำได้


เพื่อทำความเข้าใจว่าคุณใช้refsกับอะไรstate / propsลองมาดูหลักการออกแบบบางประการที่ React ดังต่อไปนี้

เอกสารต่อการตอบสนองเกี่ยวกับrefs

หลีกเลี่ยงการใช้การอ้างอิงสำหรับสิ่งที่สามารถทำได้อย่างเปิดเผย

หลักการออกแบบของ Per React เกี่ยวกับEscape Hatches

หากรูปแบบบางอย่างที่เป็นประโยชน์สำหรับการสร้างแอปนั้นยากที่จะแสดงออกในลักษณะที่เปิดเผยได้เราจะจัดเตรียม API ที่จำเป็นสำหรับมัน (และลิงก์ไปยังอ้างอิงที่นี่)

ซึ่งหมายความว่าทีมงานของ React แนะนำให้หลีกเลี่ยงrefsและใช้state / propsสำหรับทุกสิ่งที่สามารถทำได้ในรูปแบบที่ตอบสนอง / ประกาศ

@Tyler McGinnis ได้ให้คำตอบที่ดีมากโดยระบุเช่นกันว่า

วิธีที่ถูกต้อง (และมีประโยชน์มาก) ในการใช้การอ้างอิงคือเมื่อคุณใช้เพื่อรับค่าบางอย่างจาก DOM ...

แม้ว่าคุณจะทำได้ แต่คุณก็กำลังต่อต้านปรัชญาของ React state / propsถ้าคุณมีความคุ้มค่าในการป้อนข้อมูลก็แน่นอนที่สุดมาจาก เพื่อให้โค้ดมีความสอดคล้องและคาดเดาได้คุณควรยึดติดกับที่state / propsนั่นด้วย ฉันรับทราบความจริงที่ว่าrefsบางครั้งให้วิธีแก้ปัญหาที่รวดเร็วกว่าดังนั้นหากคุณพิสูจน์แนวคิดได้ก็ยอมรับได้ว่ารวดเร็วและสกปรก

สิ่งนี้ทำให้เรามีกรณีการใช้งานที่เป็นรูปธรรมหลายประการสำหรับrefs

การจัดการโฟกัสการเลือกข้อความหรือการเล่นสื่อ ทริกเกอร์ภาพเคลื่อนไหวที่จำเป็น การผสานรวมกับไลบรารี DOM ของ บริษัท อื่น


5

กระทู้นี้เก่าแล้ว

ฉันจะแบ่งปันประสบการณ์เล็ก ๆ น้อย ๆ ของฉันเกี่ยวกับกรณีหนึ่งในเรื่องนั้น

ฉันกำลังทำงานกับองค์ประกอบขนาดใหญ่ (414 บรรทัด) ที่มีอินพุต 'ไดนามิก' จำนวนมากและข้อมูลแคชจำนวนมากที่เกี่ยวข้อง (ฉันไม่ได้ทำงานคนเดียวบนหน้านี้และความรู้สึกของฉันบอกฉันว่าโครงสร้างของโค้ดอาจจะแยกออกได้ดีกว่า แต่ก็ไม่ใช่ประเด็น (อาจเป็นได้ แต่ฉันกำลังจัดการกับมัน)

ครั้งแรกฉันทำงานกับรัฐเพื่อจัดการกับค่าของปัจจัยการผลิต:

  const [inputsValues, setInputsValues] = useState([])
  const setInputValue = (id, value) => {
    const arr = [...inputsValues]
    arr[id] = value
    setInputsValues(arr)
  }

และแน่นอนในปัจจัยการผลิต:

value={inputsValues[id] || ''}
onChange={event => setInputValue(id, event.target.value)}

การแสดงผลนั้นหนักมากจนการเปลี่ยนแปลงอินพุตขาด ๆ หาย ๆ เป็น **** (อย่าพยายามกดปุ่มค้างไว้ข้อความจะปรากฏหลังจากหยุดชั่วคราวเท่านั้น)

ฉันแน่ใจว่าฉันสามารถหลีกเลี่ยงสิ่งนี้ได้โดยใช้การอ้างอิง

ลงเอยเช่นนี้:

  const inputsRef = useRef([])

และในอินพุต:

ref={input => (inputsRef.current[id] = input)}

[ในกรณีของฉัน Input คือ Material-UI TextField ดังนั้นจึงเป็น:

inputRef={input => (inputsRef.current[id] = input)}

]

ด้วยเหตุนี้จึงไม่มีการเรนเดอร์อินพุตจึงราบรื่น funcionality ทำงานในลักษณะเดียวกัน มันจะช่วยประหยัดรอบและการคำนวณดังนั้นพลังงานก็เช่นกัน ทำเพื่อแผ่นดิน x)

ข้อสรุปของฉัน: สามารถใช้ useRef สำหรับค่าอินพุตได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.