Đặt vấn đề: Viết component CheckBox với giao diện gồm: 1 tag Input và 2 tag text thể hiện trạng thái check hoặc uncheck của CheckBox, sao cho người dùng có thể dễ dàng thay đổi thứ tự của của các tag:
Ví dụ:
Trong trường hợp này ta có thể sử dụng Compound component để giải quyết vấn đề trên. Đây là 1 pattern cho phép người dùng thay đổi giao diện và thứ tự của các thành phần con mà không làm ảnh hưởng đến chức năng chính của component.
Phương pháp thực hiện:
- Các thành phần con sẽ được viết dưới dạng function component và được xem là static properties của component cha
- Sử dụng hàm React.Children.map để truyền các state của component cha xuống cho component con.
Các bước thực hiện:
- Bước 1: Viết các thành phần con
static Checked = ({ checked, children }) => (checked ? children : null);
static UnChecked = ({ checked, children }) => (checked ? null : children);
static Input = ({ checked, onCheck, ...props }) => (
<Input type="checkbox" checked={checked} onClick={onCheck} {...props} />
);
- Bước 2: Truyền state của component cha xuống component con
render() {
return React.Children.map(this.props.children, childElement =>
React.cloneElement(childElement, {
checked: this.state.checked,
onCheck: this.onCheck
})
);
}
Full code:
import React from "react";
import ReactDOM from "react-dom";
import { Input } from "reactstrap";
import "./styles.css";
class CheckBox extends React.Component {
static Checked = ({ checked, children }) => (checked ? children : null);
static UnChecked = ({ checked, children }) => (checked ? null : children);
static Input = ({ checked, onCheck, ...props }) => (
<Input type="checkbox" checked={checked} onClick={onCheck} {...props} />
);
state = {
checked: true
};
onCheck = () =>
this.setState(
({ checked }) => ({ checked: !checked }),
() => this.props.handleCheck(this.state.checked)
);
render() {
return React.Children.map(this.props.children, childElement =>
React.cloneElement(childElement, {
checked: this.state.checked,
onCheck: this.onCheck
})
);
}
}
function App() {
function handleCheck(...args) {
console.log("handleCheck", ...args);
}
return (
<CheckBox handleCheck={handleCheck}>
<CheckBox.Checked>CheckBox is checked</CheckBox.Checked>
<CheckBox.Input />
<CheckBox.UnChecked>CheckBox is uncheck</CheckBox.UnChecked>
</CheckBox>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
