ตอบสนอง: เหตุใดองค์ประกอบลูกจึงไม่อัปเดตเมื่อมีการเปลี่ยนแปลงเสา


137

เหตุใดในตัวอย่างโค้ดหลอกต่อไปนี้ Child จึงไม่แสดงผลอีกครั้งเมื่อคอนเทนเนอร์เปลี่ยน foo.bar

Container {
  handleEvent() {
    this.props.foo.bar = 123
  },

  render() {
    return <Child bar={this.props.foo.bar} />
}

Child {
  render() {
    return <div>{this.props.bar}</div>
  }
}

แม้ว่าฉันจะเรียกforceUpdate()หลังจากแก้ไขค่าในคอนเทนเนอร์แล้ว Child ก็ยังคงแสดงค่าเดิม


5
นี่คือรหัสของคุณหรือไม่ ดูเหมือนว่าจะไม่ใช่รหัสการตอบสนองที่ถูกต้อง

ฉันคิดว่าค่าอุปกรณ์ประกอบฉากไม่ควรเปลี่ยนในส่วนประกอบคอนเทนเนอร์แทนที่จะควรเปลี่ยนในองค์ประกอบหลักโดย setState และสถานะนั้นควรจะแมปกับอุปกรณ์ประกอบฉากคอนเทนเนอร์
Piyush Patel

ใช้ตัวดำเนินการกระจายเช่นนี้ <Child bar = {... this.props.foo.bar} />
Sourav Singh

@AdrianWydmanski และอีก 5 คนที่โหวต: en.wikipedia.org/wiki/Pseudocode
David Newcomb

อุปกรณ์ประกอบฉาก @PiyushPatel ได้รับการอัปเดตเมื่อคอมโพเนนต์ถูกแสดงซ้ำในตำแหน่งดังตัวอย่างของรหัสหลอกที่แสดง อีกตัวอย่างหนึ่งเช่นการใช้<Route exact path="/user/:email" component={ListUserMessagePage} />ลิงก์ในหน้าเดียวกันจะอัปเดตอุปกรณ์ประกอบฉากโดยไม่ต้องสร้างอินสแตนซ์ใหม่และเรียกใช้เหตุการณ์วงจรชีวิตตามปกติ
David Newcomb

คำตอบ:


94

อัปเดตลูกให้มีแอตทริบิวต์ "คีย์" เท่ากับชื่อ คอมโพเนนต์จะแสดงผลใหม่ทุกครั้งที่มีการเปลี่ยนแปลงคีย์

Child {
  render() {
    return <div key={this.props.bar}>{this.props.bar}</div>
  }
}

5
ขอบคุณสำหรับสิ่งนี้. ฉันใช้ร้านค้า redux และไม่สามารถรับคอมโพเนนต์ของฉันเพื่อเรนเดอร์ใหม่ได้จนกว่าฉันจะเพิ่มคีย์ (ฉันใช้ไลบรารี uuid เพื่อสร้างคีย์แบบสุ่มและใช้งานได้)
Maiya

การใช้ hooks ลูกของฉันจะไม่แสดงผลอีกครั้งเมื่อตั้งค่าสถานะบนอาร์เรย์ที่มีอยู่ การแฮ็ก (อาจเป็นความคิดที่ไม่ดี) ของฉันคือการตั้งค่าสถานะของดัมมี่พร็อพพร้อมกันและเพิ่มเข้าไปในอาร์เรย์การพึ่งพา useEffect: [props.notRenderingArr, props.dummy]พึ่งพา: ถ้าความยาวของอาร์เรย์เสมอเปลี่ยนแปลงคุณสามารถตั้งอาร์เรย์ useEffect [props.notRenderingArr.length]พึ่งพา
ฮิปโนซิส

5
นี่คือสิ่งที่ฉันต้องการเช่นกัน ฉันงงว่าเมื่อไหร่ที่keyจำเป็น vs just setState? ฉันมีลูกบางคนที่ต้องพึ่งพาสถานะของพ่อแม่ แต่พวกเขาไม่ได้กระตุ้นให้เกิดการเรนเดอร์ซ้ำ ...
dcsan

คำตอบที่ดี แต่ทำไมพฤติกรรมนี้?
Rishav

1
ฉันใช้ดัชนีเป็นกุญแจสำคัญ แต่มันทำงานไม่ถูกต้อง ตอนนี้ฉันใช้ uuid และมันสมบูรณ์แบบ :) ขอบคุณ @Maiya
Ali Rehman

91

เพราะเด็ก ๆ จะไม่แสดงผลหากอุปกรณ์ประกอบฉากของผู้ปกครองเปลี่ยนไป แต่ถ้า STATE เปลี่ยนไป :)

สิ่งที่คุณกำลังแสดงคือ https://facebook.github.io/react/tips/communicate-between-components.html

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

คุณต้องตั้งค่าสถานะบางอย่างเป็นระดับบนสุดจากนั้นแสดงผลลูกในสถานะการเปลี่ยนแปลงของผู้ปกครอง สิ่งนี้สามารถช่วยได้ https://facebook.github.io/react/tips/expose-component-functions.html


6
เหตุใด setState จึงทำให้ re-render แต่ forceUpdate ไม่ใช่ นอกจากนี้ยังมีหัวข้อเล็กน้อย แต่ส่วนประกอบจะได้รับการอัปเดตอย่างไรเมื่ออุปกรณ์ประกอบฉากถูกส่งผ่านจาก redux และสถานะได้รับการอัปเดตผ่านการกระทำ
Tuomas Toivonen

1
อุปกรณ์ประกอบฉากจะไม่อัปเดตแม้ว่าคุณจะอัปเดตส่วนประกอบอุปกรณ์ประกอบฉากที่คุณส่งผ่านก็ยังคงอยู่ที่นั่น Flux เป็นอีกหัวข้อที่ใช่ :)
François Richard

3
state! = props คุณต้องอ่านเพิ่มเติมเกี่ยวกับสิ่งนั้น คุณไม่ทำการอัปเดตด้วยอุปกรณ์ประกอบฉาก
François Richard

คุณสามารถดูได้โดยตรงในซอร์สโค้ดไม่ใช่กระบวนการเดียวกัน
Webwoman

ดังนั้นสิ่งที่คุณพูดในที่นี้มีการเปลี่ยนแปลงหรือฉันเข้าใจไม่ถูกต้องฉันตั้งคำถามสำหรับสิ่งนั้น stackoverflow.com/questions/58903921/…
ILoveReactAndNode

52

ผมมีปัญหาเหมือนกัน. นี่คือวิธีแก้ปัญหาของฉันฉันไม่แน่ใจว่านั่นเป็นแนวทางปฏิบัติที่ดีบอกฉันว่าไม่:

state = {
  value: this.props.value
};

componentDidUpdate(prevProps) {
  if(prevProps.value !== this.props.value) {
    this.setState({value: this.props.value});
  }
}

UPD: ตอนนี้คุณสามารถทำสิ่งเดียวกันโดยใช้ React Hooks: (เฉพาะในกรณีที่ส่วนประกอบเป็นฟังก์ชัน)

const [value, setValue] = useState(propName);
// This will launch only if propName value has chaged.
useEffect(() => { setValue(propName) }, [propName]);

3
นี่เป็นคำตอบที่ถูกต้องแน่นอนไม่ต้องพูดถึงคำที่ง่ายที่สุด
Guilherme Ferreira

1
ฉันกำลังใช้แนวทางนี้ด้วย
ดิบๆ

@ vancy-pants componentDidUpdateในกรณีนี้จะอยู่ในองค์ประกอบ Child
Nick Friskel

4
คุณไม่จำเป็นและไม่ควรเปลี่ยนอุปกรณ์ประกอบฉากให้อยู่ในองค์ประกอบย่อย เพียงใช้อุปกรณ์ประกอบฉากโดยตรง ในFunctionComponentsนั้นจะอัปเดตส่วนประกอบลูกโดยอัตโนมัติหากอุปกรณ์ประกอบฉากเปลี่ยนไป
oemera

1
วิธีนี้ยังใช้ได้ผลเมื่อคุณมีอุปกรณ์ประกอบฉากในส่วนประกอบลูกที่ได้มาจากรัฐแม่
Chefk5

11

ตามองค์ประกอบปรัชญา React ไม่สามารถเปลี่ยนอุปกรณ์ประกอบฉากได้ พวกเขาควรได้รับจากผู้ปกครองและควรไม่เปลี่ยนรูป ผู้ปกครองเท่านั้นที่สามารถเปลี่ยนอุปกรณ์ประกอบฉากของบุตรหลานได้

คำอธิบายที่ดี สถานะและอุปกรณ์ประกอบฉาก

อ่านกระทู้นี้ด้วยเหตุใดฉันจึงไม่สามารถอัปเดตอุปกรณ์ประกอบฉากใน react.js ได้


นี่ยังหมายความว่าคอนเทนเนอร์ไม่สามารถปรับเปลี่ยนอุปกรณ์ประกอบฉากที่ได้รับจากร้านค้า redux?
Tuomas Toivonen

3
คอนเทนเนอร์ไม่ได้รับอุปกรณ์ประกอบฉากโดยตรงจากร้านค้าพวกเขาได้รับจากการอ่านส่วนหนึ่งของต้นไม้สถานะ redux (งง ??) !! ความสับสนเป็นเพราะเราไม่รู้เกี่ยวกับฟังก์ชันมหัศจรรย์เชื่อมต่อโดย react-redux หากคุณเห็นซอร์สโค้ดของวิธีการเชื่อมต่อโดยทั่วไปจะสร้างส่วนประกอบคำสั่งซื้อที่สูงขึ้นซึ่งมีสถานะที่มีคุณสมบัติ storeState และสมัครเป็นสมาชิกของร้านค้า redux เมื่อ storeState เปลี่ยนแปลงการแสดงผลทั้งหมดจะเกิดขึ้นและอุปกรณ์ประกอบฉากที่แก้ไขจะถูกส่งไปยังคอนเทนเนอร์โดยการอ่านสถานะที่เปลี่ยนแปลง หวังว่านี่จะตอบคำถาม
Sujan Thakare

คำอธิบายที่ดีการคิดถึงองค์ประกอบลำดับที่สูงขึ้นช่วยให้ฉันเข้าใจสิ่งที่เกิดขึ้น
Tuomas Toivonen

7

คุณควรใช้setStateฟังก์ชัน ถ้าไม่รัฐจะไม่บันทึกการเปลี่ยนแปลงไม่ว่าคุณจะใช้ forceUpdate อย่างไร

Container {
    handleEvent= () => { // use arrow function
        //this.props.foo.bar = 123
        //You should use setState to set value like this:
        this.setState({foo: {bar: 123}});
    };

    render() {
        return <Child bar={this.state.foo.bar} />
    }
    Child {
        render() {
            return <div>{this.props.bar}</div>
        }
    }
}

รหัสของคุณไม่ถูกต้อง ฉันไม่สามารถทดสอบรหัสนี้ได้


ควร<Child bar={this.state.foo.bar} />หรือไม่?
Josh Broadhurst

ขวา. ฉันอัปเดตคำตอบ แต่อย่างที่บอกว่านี่อาจไม่ใช่รหัสที่ถูกต้อง เพียงแค่คัดลอกจากคำถาม
JamesYin

5

เมื่อสร้างการตอบสนองจากส่วนประกอบและfunctionsuseState

const [drawerState, setDrawerState] = useState(false);

const toggleDrawer = () => {
      // attempting to trigger re-render
      setDrawerState(!drawerState);
};

นี้จะไม่ทำงาน

         <Drawer
            drawerState={drawerState}
            toggleDrawer={toggleDrawer}
         />

นี้ไม่ทำงาน (เพิ่มกุญแจ)

         <Drawer
            drawerState={drawerState}
            key={drawerState}
            toggleDrawer={toggleDrawer}
         />

4

ยืนยันการเพิ่มคีย์ใช้งานได้ ฉันอ่านเอกสารเพื่อพยายามทำความเข้าใจว่าทำไม

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

การเพิ่ม Key forces React เพื่อแสดงผลคอมโพเนนต์ใหม่จึงเป็นการรีเซ็ต State สำหรับคอมโพเนนต์ใหม่นั้น

https://reactjs.org/docs/reconciliation.html#recursing-on-children


1

ใช้ฟังก์ชัน setState คุณสามารถทำได้

       this.setState({this.state.foo.bar:123}) 

ภายในวิธีจัดการเหตุการณ์

เมื่อสถานะได้รับการอัปเดตจะทำให้เกิดการเปลี่ยนแปลงและการแสดงผลใหม่จะเกิดขึ้น


1
ควรเป็น this.setState ({foo.bar:123}) ใช่ไหม
Charith Jayasanka

นี่ยังไม่ได้รวบรวม⬆ ฉันคิดว่าคุณหมายถึง this.setState ({foo: {bar: 123}})
Avius

0

คุณควรกำหนดให้เด็กเป็นส่วนประกอบที่ใช้งานได้หากไม่ได้รักษาสถานะใด ๆ และเพียงแค่แสดงผลอุปกรณ์ประกอบฉากแล้วเรียกจากผู้ปกครอง อีกทางเลือกหนึ่งคือคุณสามารถใช้ hooks กับคอมโพเนนต์การทำงาน (useState) ซึ่งจะทำให้คอมโพเนนต์ไร้สถานะแสดงผลอีกครั้ง

นอกจากนี้คุณไม่ควรเปลี่ยนโพรปัสเนื่องจากไม่เปลี่ยนรูป รักษาสถานะของส่วนประกอบ

Child = ({bar}) => (bar);

0

ฉันพบปัญหาเดียวกัน ฉันมีTooltipส่วนประกอบที่ได้รับshowTooltipprop ซึ่งฉันกำลังอัปเดตParentตามองค์ประกอบตามifเงื่อนไขมันกำลังได้รับการอัปเดตในParentองค์ประกอบ แต่Tooltipส่วนประกอบไม่แสดงผล

const Parent = () => {
   let showTooltip = false;
   if(....){ showTooltip = true; }
   return(
      <Tooltip showTooltip={showTooltip}></Tooltip>
   )
}

ความผิดพลาดที่ฉันทำคือการประกาศshowTooltipว่าเป็นผู้ให้

ฉันรู้ว่าฉันทำอะไรผิดฉันละเมิดหลักการของการเรนเดอร์ทำงานการเปลี่ยนมันด้วยตะขอก็ทำได้

const [showTooltip, setShowTooltip] =  React.useState<boolean>(false);

0

กำหนดอุปกรณ์ประกอบฉากที่เปลี่ยนแปลงใน mapStateToProps ของวิธีการเชื่อมต่อในองค์ประกอบลูก

function mapStateToProps(state) {
  return {
    chanelList: state.messaging.chanelList,
  };
}

export default connect(mapStateToProps)(ChannelItem);

ในกรณีของฉันช่องของ channelList ได้รับการอัปเดตดังนั้นฉันจึงเพิ่ม chanelList ใน mapStateToProps


0
export default function DataTable({ col, row }) {
  const [datatable, setDatatable] = React.useState({});
  useEffect(() => {
    setDatatable({
      columns: col,
      rows: row,
    });
  /// do any thing else 
  }, [row]);

  return (
    <MDBDataTableV5
      hover
      entriesOptions={[5, 20, 25]}
      entries={5}
      pagesAmount={4}
      data={datatable}
    />
  );
}

ตัวอย่างนี้ใช้useEffectเพื่อเปลี่ยนสถานะเมื่อมีpropsการเปลี่ยนแปลง

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