ฉันอยู่ในขั้นตอนการใช้รายการที่กรองได้ด้วย React โครงสร้างของรายการดังที่แสดงในภาพด้านล่าง
พรีเมี่ยม
นี่คือคำอธิบายวิธีการทำงาน:
- สถานะอยู่ในองค์ประกอบระดับสูงสุดคือ
Search
องค์ประกอบ - รัฐอธิบายดังนี้:
{ มองเห็นได้: บูลีน ไฟล์: อาร์เรย์ กรอง: อาร์เรย์ แบบสอบถาม: สตริง, currentSelectedIndex: จำนวนเต็ม }
files
เป็นอาร์เรย์ที่มีพา ธ ไฟล์ที่มีขนาดใหญ่มาก (10,000 รายการเป็นจำนวนที่น่าเชื่อถือ)filtered
คืออาร์เรย์ที่กรองหลังจากผู้ใช้พิมพ์อย่างน้อย 2 อักขระ ฉันรู้ว่ามันเป็นข้อมูลอนุพันธ์และด้วยเหตุนี้จึงสามารถโต้แย้งเกี่ยวกับการจัดเก็บข้อมูลในสถานะได้ แต่จำเป็นสำหรับcurrentlySelectedIndex
ซึ่งเป็นดัชนีขององค์ประกอบที่เลือกในปัจจุบันจากรายการที่กรองแล้วผู้ใช้พิมพ์ตัวอักษรมากกว่า 2 ตัวลงใน
Input
ส่วนประกอบอาร์เรย์จะถูกกรองและสำหรับแต่ละรายการในอาร์เรย์ที่กรองResult
องค์ประกอบจะถูกแสดงผลแต่ละ
Result
องค์ประกอบจะแสดงเส้นทางแบบเต็มที่ตรงกับคำค้นหาบางส่วนและส่วนที่ตรงกันบางส่วนของเส้นทางจะถูกเน้น ตัวอย่างเช่น DOM ของคอมโพเนนต์ผลลัพธ์หากผู้ใช้พิมพ์ 'le' จะเป็นดังนี้:<li>this/is/a/fi<strong>le</strong>/path</li>
- หากผู้ใช้กดปุ่มขึ้นหรือลงในขณะที่
Input
คอมโพเนนต์เน้นการcurrentlySelectedIndex
เปลี่ยนแปลงตามfiltered
อาร์เรย์ ทำให้Result
องค์ประกอบที่ตรงกับดัชนีถูกทำเครื่องหมายว่าเลือกไว้ทำให้เกิดการแสดงผลซ้ำ
ปัญหา
ตอนแรกฉันทดสอบสิ่งนี้ด้วยอาร์เรย์ที่เล็กพอfiles
โดยใช้ React เวอร์ชันพัฒนาและทุกอย่างทำงานได้ดี
ปัญหาเกิดขึ้นเมื่อฉันต้องจัดการกับfiles
อาร์เรย์ที่ใหญ่ถึง 10,000 รายการ การพิมพ์ตัวอักษร 2 ตัวในอินพุตจะสร้างรายการขนาดใหญ่และเมื่อฉันกดปุ่มขึ้นและลงเพื่อนำทางมันจะล่าช้ามาก
ในตอนแรกฉันไม่มีองค์ประกอบที่กำหนดไว้สำหรับResult
องค์ประกอบและฉันเป็นเพียงการสร้างรายการได้ทันทีในแต่ละการเรนเดอร์ของSearch
องค์ประกอบดังต่อไปนี้:
results = this.state.filtered.map(function(file, index) {
var start, end, matchIndex, match = this.state.query;
matchIndex = file.indexOf(match);
start = file.slice(0, matchIndex);
end = file.slice(matchIndex + match.length);
return (
<li onClick={this.handleListClick}
data-path={file}
className={(index === this.state.currentlySelected) ? "valid selected" : "valid"}
key={file} >
{start}
<span className="marked">{match}</span>
{end}
</li>
);
}.bind(this));
ดังที่คุณทราบทุกครั้งที่มีการcurrentlySelectedIndex
เปลี่ยนแปลงจะทำให้เกิดการแสดงผลซ้ำและรายการจะถูกสร้างขึ้นใหม่ทุกครั้ง ฉันคิดว่าเนื่องจากฉันตั้งkey
ค่าให้กับแต่ละli
องค์ประกอบการตอบสนองจะหลีกเลี่ยงการแสดงผลli
องค์ประกอบอื่น ๆ ทั้งหมดที่ไม่มีการclassName
เปลี่ยนแปลง แต่ดูเหมือนว่าจะไม่เป็นเช่นนั้น
ฉันลงเอยด้วยการกำหนดคลาสสำหรับResult
องค์ประกอบโดยที่มันจะตรวจสอบอย่างชัดเจนว่าแต่ละResult
องค์ประกอบควรแสดงผลอีกครั้งหรือไม่โดยขึ้นอยู่กับว่าก่อนหน้านี้ถูกเลือกหรือไม่และขึ้นอยู่กับอินพุตของผู้ใช้ปัจจุบัน:
var ResultItem = React.createClass({
shouldComponentUpdate : function(nextProps) {
if (nextProps.match !== this.props.match) {
return true;
} else {
return (nextProps.selected !== this.props.selected);
}
},
render : function() {
return (
<li onClick={this.props.handleListClick}
data-path={this.props.file}
className={
(this.props.selected) ? "valid selected" : "valid"
}
key={this.props.file} >
{this.props.children}
</li>
);
}
});
และรายการจะถูกสร้างขึ้นในขณะนี้:
results = this.state.filtered.map(function(file, index) {
var start, end, matchIndex, match = this.state.query, selected;
matchIndex = file.indexOf(match);
start = file.slice(0, matchIndex);
end = file.slice(matchIndex + match.length);
selected = (index === this.state.currentlySelected) ? true : false
return (
<ResultItem handleClick={this.handleListClick}
data-path={file}
selected={selected}
key={file}
match={match} >
{start}
<span className="marked">{match}</span>
{end}
</ResultItem>
);
}.bind(this));
}
สิ่งนี้ทำให้ประสิทธิภาพดีขึ้นเล็กน้อยแต่ก็ยังไม่ดีพอ สิ่งนี้คือตอนที่ฉันทดสอบกับสิ่งที่ตอบสนองเวอร์ชันที่ใช้งานจริงนั้นทำงานได้อย่างราบรื่นไม่มีความล่าช้าเลย
ด้านล่าง
ความแตกต่างที่เห็นได้ชัดเจนระหว่าง React เวอร์ชันพัฒนาและเวอร์ชันที่ใช้งานจริงเป็นเรื่องปกติหรือไม่
ฉันเข้าใจ / ทำอะไรผิดหรือเปล่าเมื่อฉันคิดว่า React จัดการรายการอย่างไร
อัพเดท 14-11-2559
ฉันได้พบการนำเสนอของ Michael Jackson ซึ่งเขาจัดการกับปัญหาที่คล้ายกับเรื่องนี้มาก: https://youtu.be/7S8v8jfLb1Q?t=26m2s
วิธีแก้ปัญหาคล้ายกับที่เสนอโดยคำตอบของ AskarovBeknar ด้านล่าง
อัพเดท 14-4-2018
เนื่องจากเห็นได้ชัดว่านี่เป็นคำถามยอดนิยมและสิ่งต่าง ๆ ได้ดำเนินไปแล้วเนื่องจากคำถามเดิมถูกถามในขณะที่ฉันขอแนะนำให้คุณดูวิดีโอที่เชื่อมโยงด้านบนเพื่อให้เข้าใจรูปแบบเสมือนจริงฉันขอแนะนำให้คุณใช้React Virtualizedห้องสมุดหากคุณไม่ต้องการประดิษฐ์วงล้อใหม่