เพิ่มส่วนประกอบย่อยแบบไดนามิกใน React


89

เป้าหมายของฉันคือการเพิ่มส่วนประกอบแบบไดนามิกในเพจ / คอมโพเนนต์หลัก

ฉันเริ่มต้นด้วยเทมเพลตตัวอย่างพื้นฐานเช่นนี้:

main.js:

var App = require('./App.js');
var SampleComponent = require('./SampleComponent.js');
ReactDOM.render(<App/>, document.body);
ReactDOM.render(<SampleComponent name="SomeName"/>, document.getElementById('myId'));

App.js:

var App = React.createClass({
    render: function() {
        return (
            <div>
                <h1>App main component! </h1>
                <div id="myId">myId div</div>
            </div>

        );
    }

});

SampleComponent.js:

var SampleComponent = React.createClass({
    render: function() {
        return (
            <div>
                <h1>Sample Component! </h1>
            </div>
        );
    }
});

ที่นี่SampleComponentติดตั้งกับ<div id="myId"></div>โหนดซึ่งเขียนไว้ล่วงหน้าในApp.jsเทมเพลต แต่จะเกิดอะไรขึ้นถ้าฉันต้องการเพิ่มองค์ประกอบไม่ จำกัด จำนวนลงในองค์ประกอบของแอป? เห็นได้ชัดว่าฉันไม่สามารถมีdiv ที่จำเป็นทั้งหมดนั่งอยู่ที่นั่นได้

หลังจากอ่านบทแนะนำบางส่วนแล้วฉันยังไม่เข้าใจว่าส่วนประกอบต่างๆถูกสร้างและเพิ่มไปยังองค์ประกอบหลักแบบไดนามิกได้อย่างไร วิธีการทำคืออะไร?


2
มีสาเหตุหรือไม่ที่ส่วนประกอบทั้งสองของคุณเชื่อมต่อกับองค์ประกอบต่าง 99% ของแอป React เรียกเพียงReactDOM.renderครั้งเดียวและส่วนประกอบอื่น ๆ ทั้งหมดเป็นลูกของโหนด 'root'
azium

1
ไม่ตอนนี้ฉันเข้าใจแล้วว่านี่ไม่ใช่วิธีที่ถูกต้อง :)
Justin Trevein

คำตอบ:


70

คุณต้องส่งส่วนประกอบของคุณในฐานะลูกเช่นนี้:

var App = require('./App.js');
var SampleComponent = require('./SampleComponent.js');
ReactDOM.render(
    <App>
        <SampleComponent name="SomeName"/> 
    <App>, 
    document.body
);

จากนั้นต่อท้ายในเนื้อหาของส่วนประกอบ:

var App = React.createClass({
    render: function() {
        return (
            <div>
                <h1>App main component! </h1>
                {
                    this.props.children
                }
            </div>
        );
    }
});

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

var App = React.createClass({

    getInitialState: function(){
        return [
            {id:1,name:"Some Name"}
        ]
    },

    addChild: function() {
        // State change will cause component re-render
        this.setState(this.state.concat([
            {id:2,name:"Another Name"}
        ]))
    }

    render: function() {
        return (
            <div>
                <h1>App main component! </h1>
                <button onClick={this.addChild}>Add component</button>
                {
                    this.state.map((item) => (
                        <SampleComponent key={item.id} name={item.name}/>
                    ))
                }
            </div>
        );
    }

});

2
ขอบคุณ! ฉันพลาดข้อเท็จจริงที่ว่าส่วนประกอบต่างๆสามารถกำหนดได้ใน render () ตามสถานะของมัน คำตอบของคุณที่นี่เป็นคำตอบที่สมบูรณ์ที่สุด (กล่าวถึงสถานะที่มีส่วนประกอบ) และตอบคำถามได้ตรงประเด็น :)
Justin Trevein

คุณส่งอุปกรณ์ประกอบฉากให้กับเด็ก ๆ ที่ต่อท้ายได้อย่างไร?
BrightIntelDusk

1
ดังนั้นเพื่อติดตามสิ่งนี้: หากฉันต้องการสร้างแอพหน้าเดียวที่มีหลายแท็บและหน้าต่างป๊อปอัปจากปุ่มต่างๆฉันต้องดำเนินการต่อและแสดงผลส่วนประกอบเหล่านั้น (ว่างเปล่า) ซ่อน (อย่างใดอย่างหนึ่ง) แล้วแก้ไขสถานะเพื่อให้ พวกเขา "ปรากฏ" ในเวลาที่เหมาะสม? หากคุณพยายามสร้างแอพหน้าเดียวแบบหลายแท็บใน React เป็นวิธีที่ดีที่สุดที่จะคิดหรือไม่? หรือฉันขาดอะไรไป? ขอขอบคุณ!
Elisabeth

1
@ เอลิซาเบ ธ ใช่ถูกต้อง จริงๆแล้วคุณมีสองตัวเลือกหลัก: แสดงทุกอย่างเสมอและซ่อนสิ่งต่างๆโดยใช้ CSS ใช้คลาส CSS หรือสไตล์อินไลน์ตามเงื่อนไข หรือแสดงผลสิ่งต่างๆตามเงื่อนไขส่งคืนองค์ประกอบการตอบสนองหรือค่าว่างขึ้นอยู่กับสถานะแอปของคุณ สองวิธีนี้มีข้อดีข้อเสียและมักใช้ทั้งสองอย่างในแอพเดียวกันสำหรับส่วนประกอบที่แตกต่างกันขึ้นอยู่กับความต้องการของคุณ
Nikolai Mavrenkov

1
ขอบคุณ Nikolai! นั่นช่วยเสริมสร้างสิ่งต่างๆในใจของฉันเกี่ยวกับ React มันเป็นวิธีการออกแบบแอพและคิดถึง DOM ที่แตกต่างไปจากที่ฉันใช้กับ JavaScript ธรรมดาและ jQuery
Elisabeth

7

ครั้งแรกที่ฉันจะไม่ใช้ document.body เพิ่มคอนเทนเนอร์เปล่าแทน:

index.html:

<html>
    <head></head>
    <body>
        <div id="app"></div>
    </body>
</html>

จากนั้นเลือกที่จะแสดงเฉพาะ<App />องค์ประกอบของคุณ:

main.js:

var App = require('./App.js');
ReactDOM.render(<App />, document.getElementById('app'));

ภายในApp.jsคุณสามารถนำเข้าส่วนประกอบอื่น ๆ ของคุณและละเว้นโค้ดการแสดงผล DOM ของคุณโดยสิ้นเชิง:

App.js:

var SampleComponent = require('./SampleComponent.js');

var App = React.createClass({
    render: function() {
        return (
            <div>
                <h1>App main component!</h1>
                <SampleComponent name="SomeName" />
            </div>
        );
    }
});

SampleComponent.js:

var SampleComponent = React.createClass({
    render: function() {
        return (
            <div>
                <h1>Sample Component!</h1>
            </div>
        );
    }
});

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


ไม่มีปัญหาฉันแค่เห็นใครบางคนคัดลอกมาวางแล้วใช้เวลาหลายชั่วโมงกับมัน ...
Neil Twist

6

แบ่งปันวิธีแก้ปัญหาของฉันที่นี่ตามคำตอบของคริส หวังว่ามันจะช่วยคนอื่นได้

ฉันต้องการต่อท้ายองค์ประกอบลูกแบบไดนามิกใน JSX ของฉัน แต่วิธีที่ง่ายกว่าการตรวจสอบเงื่อนไขในคำสั่งส่งคืนของฉัน ฉันต้องการแสดงตัวโหลดในกรณีที่องค์ประกอบลูกยังไม่พร้อม นี่คือ:

export class Settings extends React.PureComponent {
  render() {
    const loading = (<div>I'm Loading</div>);
    let content = [];
    let pushMessages = null;
    let emailMessages = null;

    if (this.props.pushPreferences) {
       pushMessages = (<div>Push Content Here</div>);
    }
    if (this.props.emailPreferences) {
      emailMessages = (<div>Email Content Here</div>);
    }

    // Push the components in the order I want
    if (emailMessages) content.push(emailMessages);
    if (pushMessages) content.push(pushMessages);

    return (
      <div>
        {content.length ? content : loading}
      </div>
    )
}

ตอนนี้ฉันรู้แล้วว่าฉันสามารถใส่{pushMessages}และลง{emailMessages}ในreturn()ด้านล่างของฉันได้โดยตรงแต่ถ้าฉันมีเนื้อหาที่มีเงื่อนไขมากกว่านี้ฉันreturn()ก็จะดูรก


4

ประการแรกคำเตือน: คุณไม่ควรคนจรจัดกับ DOM ที่จัดการโดย React ซึ่งคุณกำลังทำโดยการโทร ReactDOM.render(<SampleComponent ... />);

ด้วย React คุณควรใช้ SampleComponent โดยตรงในแอพหลัก

var App = require('./App.js');
var SampleComponent = require('./SampleComponent.js');
ReactDOM.render(<App/>, document.body);

เนื้อหาของคอมโพเนนต์ของคุณไม่เกี่ยวข้อง แต่ควรใช้ในลักษณะนี้:

var App = React.createClass({
    render: function() {
        return (
            <div>
                <h1>App main component! </h1>
                <SampleComponent name="SomeName"/>
            </div>
        );
    }
});

จากนั้นคุณสามารถขยายส่วนประกอบของแอปเพื่อใช้รายการ

var App = React.createClass({
    render: function() {
        var componentList = [
            <SampleComponent name="SomeName1"/>,
            <SampleComponent name="SomeName2"/>
        ]; // Change this to get the list from props or state
        return (
            <div>
                <h1>App main component! </h1>
                {componentList}
            </div>
        );
    }
});

ฉันอยากจะแนะนำให้คุณดูเอกสารการตอบสนองจากนั้นทำตามคำแนะนำ "เริ่มต้นใช้งาน" เวลาที่คุณใช้ไปนั้นจะจ่ายออกในภายหลัง

https://facebook.github.io/react/index.html


อาร์เรย์จะเติมองค์ประกอบย่อยโดยไม่ต้องแมปอย่างไร
solanki ...

1
@solanki ... จำเป็นต้องมีการทำแผนที่เฉพาะเมื่อรายการไม่ใช่รายการส่วนประกอบของปฏิกิริยา รายการที่นี่เป็นสองSampleComponentวินาทีซึ่งไม่จำเป็นต้องมีการแมป หากรายชื่อนั้นเป็นรายชื่อก็จะต้องมีการแมปกับคอมโพเนนต์ React
Neil Twist

@solanki ... โปรดจำไว้ว่าผลลัพธ์ของการทำแผนที่เป็นเพียงรายการอื่น
Neil Twist

1
สิ่งที่ฉันกำลังมองหา กรณีการใช้งานของฉันจำเป็นต้องพุชคอมโพเนนต์ JSX เป็นทางเลือกที่<div>กำหนดให้กับตัวแปรที่ถูกแทรกลงใน JSX เช่นเดียวกับ{content}ในคำสั่ง return ของฉัน การใช้อาร์เรย์ว่างนั้นง่ายมาก!
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.