插件窝 干货文章 ReactJS 设计模式:编写健壮且可扩展的组件

ReactJS 设计模式:编写健壮且可扩展的组件

组件 strong const react 745    来源:    2024-10-20

reactjs 中的设计模式为应用程序开发中的常见问题提供了标准化且经过验证的解决方案。使用这些模式不仅使您的代码更具可读性和可维护性,而且还增强了其可扩展性和健壮性。让我们深入研究一些最流行的 reactjs 设计模式,并通过示例来说明它们的用法。

1. 容器和表示组件模式

容器和展示模式将组件分为两类:

  • 展示组件:关注事物的外观(ui)。
  • 容器组件:关注事物如何工作(逻辑和状态管理)。

这种分离可以实现更好的可重用性、更容易的测试和更清晰的代码。

示例:展示和容器组件

// presentational component: displaying user list (userlist.js)
import react from 'react';

const userlist = ({ users }) => (
  
    {users.map((user) => (
  • {user.name}
  • ))}

);

export default userlist;

// container component: fetching user data (usercontainer.js)
import react, { usestate, useeffect } from 'react';
import userlist from './userlist';

const usercontainer = () => {
  const [users, setusers] = usestate([]);

  useeffect(() => {
    const fetchusers = async () => {
      const response = await fetch('https://jsonplaceholder.typicode.com/users');
      const data = await response.json();
      setusers(data);
    };
    fetchusers();
  }, []);

  return <userlist users="{users}"></userlist>;
};

export default usercontainer;

这里,userlist 是一个展示组件,它接收用户作为 props,而 usercontainer 则处理数据获取和状态管理。

2. 高阶组件(hoc)模式

a 高阶组件 (hoc) 是一个将组件作为参数并返回新组件的函数。 hoc 通常用于横切关注点,例如身份验证、日志记录或增强组件行为。

示例:创建 hoc 进行授权

// withauthorization.js (hoc for authorization)
import react from 'react';

const withauthorization = (wrappedcomponent) =&gt; {
  return class extends react.component {
    componentdidmount() {
      if (!localstorage.getitem('authtoken')) {
        // redirect to login if not authenticated
        window.location.href = '/login';
      }
    }

    render() {
      return <wrappedcomponent></wrappedcomponent>;
    }
  };
};

export default withauthorization;
// dashboard.js (component wrapped with hoc)
import react from 'react';
import withauthorization from './withauthorization';

const dashboard = () =&gt; <h1>welcome to the dashboard</h1>;

export default withauthorization(dashboard);

通过使用 withauthorization 包装 dashboard,您可以确保只有经过身份验证的用户才能访问它。

3. 渲染道具模式

render props 模式涉及使用值为函数的 prop 在组件之间共享代码。此模式对于基于特定条件或状态的动态渲染非常有用。

示例:使用渲染道具进行鼠标跟踪

// mousetracker.js (component with render props)
import react, { usestate } from 'react';

const mousetracker = ({ render }) =&gt; {
  const [position, setposition] = usestate({ x: 0, y: 0 });

  const handlemousemove = (event) =&gt; {
    setposition({ x: event.clientx, y: event.clienty });
  };

  return <div onmousemove="{handlemousemove}">{render(position)}</div>;
};

export default mousetracker;
// app.js (using render props)
import react from 'react';
import mousetracker from './mousetracker';

const app = () =&gt; (
  <mousetracker render="{({" x y> (
      <h1>
        mouse position: ({x}, {y})
      </h1>
    )}
  /&gt;
);

export default app;
</mousetracker>

mousetracker 组件使用 render prop 将鼠标位置数据传递给任何组件,使其具有高度可重用性。

4. 自定义挂钩模式

自定义 hook 允许您跨多个组件封装和重用有状态逻辑。这种模式促进了代码的可重用性和清晰的关注点分离。

示例:创建用于获取数据的自定义挂钩

// usefetch.js (custom hook)
import { usestate, useeffect } from 'react';

const usefetch = (url) =&gt; {
  const [data, setdata] = usestate(null);
  const [loading, setloading] = usestate(true);

  useeffect(() =&gt; {
    const fetchdata = async () =&gt; {
      const response = await fetch(url);
      const result = await response.json();
      setdata(result);
      setloading(false);
    };
    fetchdata();
  }, [url]);

  return { data, loading };
};

export default usefetch;
// app.js (using the custom hook)
import react from 'react';
import usefetch from './usefetch';

const app = () =&gt; {
  const { data, loading } = usefetch('https://jsonplaceholder.typicode.com/posts');

  if (loading) return <div>loading...</div>;

  return (
    
    {data.map((post) => (
  • {post.title}
  • ))}

); };

export default app;

usefetch 自定义钩子封装了数据获取逻辑,可以在不同组件之间复用。

5. 复合组件模式

复合组件模式允许组件一起工作来管理状态和行为。此模式对于构建复杂的 ui 组件(如选项卡、手风琴或下拉菜单)非常有用。

示例:使用复合组件构建选项卡

// tabs.js (parent component)
import react, { usestate } from 'react';

const tabs = ({ children }) =&gt; {
  const [activeindex, setactiveindex] = usestate(0);

  return react.children.map(children, (child, index) =&gt;
    react.cloneelement(child, { isactive: index === activeindex, setactiveindex, index })
  );
};

const tab = ({ children, isactive, setactiveindex, index }) =&gt; (
  <button onclick="{()"> setactiveindex(index)}&gt;{children}</button>
);

const tabpanel = ({ children, isactive }) =&gt; (isactive ? <div>{children}</div> : null);

tabs.tab = tab;
tabs.tabpanel = tabpanel;

export default tabs;
// app.js (using compound components)
import react from 'react';
import tabs from './tabs';

const app = () =&gt; (
  <tabs><tabs.tab>tab 1</tabs.tab><tabs.tab>tab 2</tabs.tab><tabs.tabpanel>content for tab 1</tabs.tabpanel><tabs.tabpanel>content for tab 2</tabs.tabpanel></tabs>
);

export default app;

tabs 组件管理状态,而 tab 和 tabpanel 组件协同显示选项卡内容。

6. 受控和非受控组件模式

受控组件完全由 react 状态管理,而非受控组件则依赖 dom 来获取状态。两者都有其用途,但为了一致性和可维护性,受控组件通常是首选。

示例:受控组件与不受控组件

// controlled component (textinputcontrolled.js)
import react, { usestate } from 'react';

const textinputcontrolled = () =&gt; {
  const [value, setvalue] = usestate('');

  return (
    <input type="text" value="{value}" onchange="{(e)"> setvalue(e.target.value)} /&gt;
  );
};

export default textinputcontrolled;
// uncontrolled component (textinputuncontrolled.js)
import react, { useref } from 'react';

const textinputuncontrolled = () =&gt; {
  const inputref = useref();

  const handleclick = () =&gt; {
    console.log(inputref.current.value);
  };

  return (
    
      <input type="text" ref="{inputref}"><button onclick="{handleclick}">log input value</button>
    &gt;
  );
};

export default textinputuncontrolled;

在受控组件中,react 完全控制表单状态,而在非受控组件中,状态由 dom 本身管理。

7. 钩子工厂模式

hooks 工厂模式涉及创建动态生成和管理多个状态或行为的钩子,提供灵活的方式来管理复杂逻辑。

示例:使用 hooks factory 进行动态状态管理

// usedynamicstate.js (hook factory)
import { usestate } from 'react';

const usedynamicstate = (initialstates) =&gt; {
  const states = {};
  const setters = {};

  initialstates.foreach(([key, initialvalue]) =&gt; {
    const [state, setstate] = usestate(initialvalue);
    states[key] = state;
    setters[key] = setstate;
  });

  return [states, setters];
};

export default usedynamicstate;
// App.js (Using the Hooks Factory)
import React from 'react';
import useDynamicState from './useDynamicState';

const App = () =&gt; {
  const [states, setters] = useDynamicState([
    ['name', ''],
    ['age', 0],
  ]);

  return (
    <div>
      <input type="text" value="{states.name}" onchange="{(e)"> setters

.name(e.target.value)}
      /&gt;
      <input type="number" value="{states.age}" onchange="{(e)"> setters.age(parseInt(e.target.value))}
      /&gt;
      <p>Name: {states.name}</p>
      <p>Age: {states.age}</p>
    </div>
  );
};

export default App;

这个钩子工厂动态创建和管理多个状态,提供灵活性和更简洁的代码。

结论

通过利用这些设计模式,您可以创建更健壮、可扩展和可维护的 react 应用程序。这些模式可帮助您编写符合最佳实践的干净、可重用的代码,确保您的应用程序随着时间的推移更容易开发和管理。

您想更深入地研究这些模式或探索其他主题吗?