การใช้ children
const Wrapper = ({children}) => (
<div>
<div>header</div>
<div>{children}</div>
<div>footer</div>
</div>
);
const App = ({name}) => <div>Hello {name}</div>;
const WrappedApp = ({name}) => (
<Wrapper>
<App name={name}/>
</Wrapper>
);
render(<WrappedApp name="toto"/>,node);
เรื่องนี้เป็นที่รู้จักกันtransclusion
ในเชิงมุม
children
เป็นเสาพิเศษในการตอบสนองและจะมีสิ่งที่อยู่ภายในแท็กองค์ประกอบของคุณ (ที่นี่<App name={name}/>
ที่อยู่ภายในWrapper
จึงเป็นchildren
โปรดทราบว่าคุณไม่จำเป็นต้องใช้children
ซึ่งเป็นเอกลักษณ์สำหรับส่วนประกอบและคุณสามารถใช้อุปกรณ์ประกอบฉากปกติได้เช่นกันหากคุณต้องการหรือผสมอุปกรณ์ประกอบฉากและเด็ก ๆ :
const AppLayout = ({header,footer,children}) => (
<div className="app">
<div className="header">{header}</div>
<div className="body">{children}</div>
<div className="footer">{footer}</div>
</div>
);
const appElement = (
<AppLayout
header={<div>header</div>}
footer={<div>footer</div>}
>
<div>body</div>
</AppLayout>
);
render(appElement,node);
ง่ายและดีสำหรับผู้ใช้หลายคนและฉันขอแนะนำให้ใช้กับแอพสำหรับผู้บริโภคส่วนใหญ่
แสดงผลอุปกรณ์ประกอบฉาก
เป็นไปได้ที่จะส่งผ่านฟังก์ชั่นการเรนเดอร์ไปยังส่วนประกอบรูปแบบนี้โดยทั่วไปเรียกว่าrender prop
และchildren
เสามักจะใช้เพื่อจัดเตรียมการเรียกกลับ
รูปแบบนี้ไม่ได้มีไว้สำหรับการจัดวางจริงๆ โดยทั่วไปแล้วองค์ประกอบของ wrapper จะใช้ในการควบคุมและจัดการสถานะและใช้ในการสร้างฟังก์ชั่น
ตัวอย่างเคาน์เตอร์:
const Counter = () => (
<State initial={0}>
{(val, set) => (
<div onClick={() => set(val + 1)}>
clicked {val} times
</div>
)}
</State>
);
คุณสามารถได้รับจินตนาการมากขึ้นและให้วัตถุ
<Promise promise={somePromise}>
{{
loading: () => <div>...</div>,
success: (data) => <div>{data.something}</div>,
error: (e) => <div>{e.message}</div>,
}}
</Promise>
หมายเหตุคุณไม่จำเป็นต้องใช้children
มันเป็นเรื่องของรสนิยม / API
<Promise
promise={somePromise}
renderLoading={() => <div>...</div>}
renderSuccess={(data) => <div>{data.something}</div>}
renderError={(e) => <div>{e.message}</div>}
/>
ณ วันนี้ห้องสมุดหลายแห่งกำลังใช้อุปกรณ์แสดงภาพ (บริบทการตอบโต้การตอบสนองการเคลื่อนไหวอพอลโล ... ) เพราะผู้คนมักจะพบว่า API นี้ง่ายกว่าของ HOC react-powerplugคือชุดขององค์ประกอบเรนเดอร์แบบง่าย ปฏิกิริยาตอบสนองที่ช่วยให้คุณทำองค์ประกอบ
ส่วนประกอบที่สูงกว่าการสั่งซื้อ (HOC)
const wrapHOC = (WrappedComponent) => {
class Wrapper extends React.PureComponent {
render() {
return (
<div>
<div>header</div>
<div><WrappedComponent {...this.props}/></div>
<div>footer</div>
</div>
);
}
}
return Wrapper;
}
const App = ({name}) => <div>Hello {name}</div>;
const WrappedApp = wrapHOC(App);
render(<WrappedApp name="toto"/>,node);
สูงกว่าการสั่งซื้อชิ้นส่วน / HOCโดยทั่วไปคือฟังก์ชั่นที่ใช้องค์ประกอบและส่งกลับองค์ประกอบใหม่
การใช้ชิ้นส่วนที่สูงกว่าการสั่งซื้อสามารถ performant มากกว่าการใช้children
หรือเพราะเสื้อคลุมจะมีความสามารถในการลัดวงจรการแสดงผลขั้นตอนหนึ่งไปข้างหน้าด้วยrender props
shouldComponentUpdate
PureComponent
ที่นี่เราจะใช้ เมื่อทำการเรนเดอร์แอปอีกครั้งหากWrappedApp
ชื่อ prop ไม่เปลี่ยนแปลงเมื่อเวลาผ่านไป wrapper มีความสามารถในการพูดว่า "ฉันไม่จำเป็นต้องเรนเดอร์เพราะอุปกรณ์ประกอบฉาก (อันที่จริงชื่อ) เหมือนกันก่อน" ด้วยchildren
วิธีการแก้ไขปัญหาข้างต้นแม้ว่าจะเป็น wrapper PureComponent
มันก็ไม่ได้เป็นเพราะองค์ประกอบเด็กถูกสร้างขึ้นใหม่ทุกครั้งที่ผู้ปกครองแสดงผลซึ่งหมายความว่าเสื้อคลุมจะมีโอกาสแสดงผลอีกครั้งแม้ว่าองค์ประกอบที่ห่อจะบริสุทธิ์ มีปลั๊กอิน babelที่สามารถช่วยลดปัญหานี้และให้แน่ใจว่าchildren
องค์ประกอบคงที่เมื่อเวลาผ่านไป
ข้อสรุป
ส่วนประกอบที่สูงกว่าสามารถให้ประสิทธิภาพที่ดีขึ้นแก่คุณ มันไม่ซับซ้อนนัก แต่มันดูไม่เป็นมิตรในตอนแรก
อย่าโอนย้ายฐานข้อมูลทั้งหมดของคุณไปที่ HOC หลังจากอ่านบทความนี้ เพียงจำไว้ว่าบนเส้นทางที่สำคัญของแอพของคุณคุณอาจต้องการใช้ HOC แทนการใช้โปรแกรมเสริมด้วยเหตุผลด้านประสิทธิภาพโดยเฉพาะอย่างยิ่งหากใช้ wrapper เดียวกันหลายครั้งก็คุ้มค่าที่จะพิจารณาให้เป็น HOC
Redux ใช้ในตอนแรก wrapper รันไทม์<Connect>
และเปลี่ยนในภายหลังเพื่อ HOC connect(options)(Comp)
ด้วยเหตุผลด้านประสิทธิภาพ (โดยค่าเริ่มต้น wrapper นั้นบริสุทธิ์และใช้งานshouldComponentUpdate
) นี่เป็นภาพประกอบที่สมบูรณ์แบบของสิ่งที่ฉันต้องการเน้นในคำตอบนี้
หมายเหตุหากองค์ประกอบมี API ของ render-prop โดยทั่วไปแล้วจะสร้าง HOC ให้ง่ายกว่านั้นดังนั้นหากคุณเป็นผู้แต่ง lib คุณควรเขียน render prop API ก่อนและสุดท้ายให้เป็นรุ่น HOC นี่คือสิ่งที่ Apollo ทำกับ<Query>
ส่วนประกอบ render-prop และgraphql
HOC ใช้มัน
โดยส่วนตัวแล้วฉันใช้ทั้งคู่ แต่เมื่อสงสัยฉันก็ชอบ HOC เพราะ:
- มันเป็นสำนวนที่ยิ่งใหญ่กว่าที่จะเขียน (
compose(hoc1,hoc2)(Comp)
) เปรียบเทียบกับการแสดงประกอบฉาก
- มันสามารถทำให้การแสดงของฉันดีขึ้น
- ฉันคุ้นเคยกับการเขียนโปรแกรมแบบนี้
ฉันไม่ลังเลที่จะใช้ / สร้างเครื่องมือโปรดของฉันในเวอร์ชัน HOC:
Context.Consumer
คอมพ์ของ React
- อันเป็นของ
Subscribe
- ใช้
graphql
HOC ของ Apollo แทนQuery
render prop
ในความคิดของฉันบางครั้งอุปกรณ์ประกอบฉากทำให้โค้ดอ่านง่ายขึ้นบางครั้งก็น้อย ... ฉันพยายามใช้วิธีแก้ปัญหาที่เป็นประโยชน์มากที่สุดตามข้อ จำกัด ที่ฉันมี บางครั้งการอ่านมีความสำคัญมากกว่าการแสดง เลือกอย่างชาญฉลาดและไม่ผูกมัดแนวโน้ม 2018 ของการแปลงทุกอย่างเพื่อแสดงผลอุปกรณ์