写出易维护的代码|React开发的设计模式及原则
介绍
一些设计原则
1.单一职责原则(Single-responsibility responsibility) : 每个实体(class, function, module)只应该有一个职责。例如当一个组件接收了太多的props,我们应该考虑组件是不是做了太多的事情,有没有必要进行拆分。
2.开闭原则(Open-closed principle):实体(class, function, module) 应该对扩展开放,但是对修改关闭。开闭原则意味着应该存在不直接修改的方式扩展实体的功能。
3.依赖反转原则(Dependency inversion principle):依赖于抽象,而不是具体的实现。依赖注入是一种实现依赖反转的方式。
4.不要自我重复 (Don't repeat yourself):重复代码会造成代码维护的困难。
React设计模式
Container & presentational component[2]
遵循的设计原则:
1.单一职责原则:Presentational component负责ui,Container component负责数据和行为。
示例:
import React from "react";
// Presentational component
export default function ImageList({ images, onClick }) {
return images.map((img, i) => <img src={img} key={i} onClick={onClick} />);
}
// Container component
export default class ImageListContainer extends React.Component {
constructor() {
super();
this.state = {
images: []
};
}
componentDidMount() {
fetch("https://images.com")
.then(res => res.json())
.then(({ images }) => this.setState({ images }));
}
handleClick() {
// ...
}
render() {
return <ImageList images={this.state.images} onClick={handleClick} />;
}
}
HOC
遵循的设计原则:
1.Don't repeat yourself:把可复用的逻辑放到HOC中,实现代码复用。
示例:
import React from "react";
export default function withLoader(Component, url) {
return class HOC extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
data: {},
};
}
componentDidMount() {
fetch(url)
.then((res) => res.json())
.then(({ data }) => this.setState({ data }))
.finally(() => this.setState({loading: false}))
}
render() {
if (this.state.loading) {
return <div>Loading...</div>;
}
return <Component {...this.props} data={this.state.data} />;
}
};
}
Render prop
遵循的设计原则:
1.Don't repeat yourself:把可复用的逻辑放到组件中,实现代码复用。
2.依赖反转原则:通过render prop注入渲染相关的实现。
示例:
import React from "react";
class Loader extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
data: {},
};
}
componentDidMount() {
fetch(url)
.then((res) => res.json())
.then(({ data }) => this.setState({ data }))
.finally(() => this.setState({ loading: false }));
}
render() {
if (this.state.loading) {
return <div>Loading...</div>;
}
return this.props.renderData(this.state.data);
}
}
Compound components
遵循的设计原则:
1.单一职责原则(Single-responsibility responsibility): 拆分成多个组件,每个组件承担自己的职责。
示例:
import React from "react";
const SelectContext = React.createContext({});
export function Select({ value, onChange, children }) {
const [open, setOpen] = React.useState(false);
const [val, setValue] = React.useState(value);
return (
<div className={`select`}>
<div
className="select-value"
onClick={() => {
setOpen(true);
}}
>
{val}
</div>
<SelectContext.Provider
value={{
value: val,
setOpen,
setValue: (newValue) => {
setValue(newValue);
if (value !== newValue) {
onChange(newValue);
}
},
}}
>
{open && children}
</SelectContext.Provider>
</div>
);
}
function Option({ children, value }) {
const {
setOpen,
setValue,
value: selectedValue,
} = React.useContext(SelectContext);
return (
<div
className={`select-option ${value === selectedValue ? "selected" : ""}`}
onClick={() => {
setValue(value);
setOpen(false);
}}
>
{children}
</div>
);
}
function OptionGroup({ children, label }) {
return (
<div className="select-option-group">
<div className="select-option-group-label">{label}</div>
{children}
</div>
);
}
Select.Option = Option;
Select.OptionGroup = OptionGroup;
function Demo() {
const [city, setCity] = React.useState("北京市");
return (
<Select value={city} onChange={setCity}>
<Select.Option value="北京市">北京市</Select.Option>
<Select.OptionGroup label="河北省">
<Select.Option value="石家庄市">石家庄市</Select.Option>
<Select.Option value="保定市">保定市</Select.Option>
</Select.OptionGroup>
</Select>
);
}
遵循的设计原则:
1.Don't repeat yourself:把可复用的逻辑放到自定义hooks中,实现代码复用。
示例:
import { useState, useEffect } from "react";
function useLoader(url) {
const [data, setData] = useState({});
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
fetch(url)
.then((res) => res.json())
.then(({ data }) => {
setData({ data });
})
.finally(() => setLoading(false));
}, [url]);
return { data, loading };
}
结尾
参考链接:
[1]https://reactjs.org/docs/composition-vs-inheritance.html
[2]https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
[3]https://github.com/reduxjs/react-redux/blob/master/docs/api/connect.md#connect
[4]https://relay.dev/docs/v10.1.3/fragment-container/#createfragmentcontainer
[5]https://reactjs.org/docs/composition-vs-inheritance.html
[6]https://reacttraining.com/react-router/web/api/Route/render-func
[7]https://github.com/paypal/downshift
[8]https://github.com/jaredpalmer/formik
[9]https://react.semantic-ui.com/
微信扫码关注该文公众号作者