写出易维护的代码|React开发的设计模式及原则
介绍
设计模式是最常见的,通用问题的可复用解决方案的归纳总结,通常被认为是解决该类问题的最佳实践,使用设计模式能帮助我们写出更容易维护,更健壮的代码。设计模式有很多,通常它们都会遵循一些共同的设计原则,接下来我们一起回顾下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设计模式
遵循的设计原则:
1. 单一职责原则:Presentational component负责ui,Container component负责数据和行为。
示例:
import React from "react";// Presentational componentexport default function ImageList({ images, onClick }) {return images.map((img, i) => <img src={img} key={i} onClick={onClick} />);}// Container componentexport 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} />;}}
遵循的设计原则:
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} />;}};}
遵循的设计原则:
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`}><divclassName="select-value"onClick={() => {setOpen(true);}}>{val}</div><SelectContext.Providervalue={{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 (<divclassName={`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 };}
结尾
[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/