import React, { useState } from 'react'; // 堆代码 duidaima.com // 基础按纽组件 const Button = ({ label, onClick }) => ( <button onClick={onClick}>{label}</button> ); // 基础文本组件 const TextBox = ({ value, onChange }) => ( <input type="text" value={value} onChange={onChange} /> ); // 复合组件 const LoginPanel = () => { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const handleLogin = () => { // 实现登录逻辑 console.log(`Logging in with ${username} and ${password}`); }; return ( <div className="login-panel"> <TextBox value={username} onChange={(e) => setUsername(e.target.value)} /> <TextBox value={password} onChange={(e) => setPassword(e.target.value)} /> <Button label="Login" onClick={handleLogin} /> </div> ); }; // 使用示例 const App = () => { return ( <LoginPanel /> ); }; export default App;在这个例子中,LoginPanel 是一个复合组件,它包含了两个基本组件 TextBox 和一个带有登录逻辑的 Button。
不适用于所有场景: 对于简单的场景,引入复合组件模式可能会显得繁琐和不必要。
对话框和模态框: 对话框或模态框通常包含标题、内容和操作按钮。可以使用复合式组件将这些部分拆分成独立的组件,以便在应用中以不同方式重复使用。
import React, { useState } from 'react'; const Button = ({ label, onClick }) => ( <button onClick={onClick}>{label}</button> ); const TextBox = ({ value, onChange }) => ( <input type="text" value={value} onChange={onChange} /> ); // 受控组件模式的复合组件 const ControlledLoginPanel = () => { const [loginData, setLoginData] = useState({ username: '', password: '' }); const handleInputChange = (e) => { const { name, value } = e.target; setLoginData((prevData) => ({ ...prevData, [name]: value, })); }; const handleLogin = () => { // 实现登录逻辑 console.log(`Logging in with ${loginData.username} and ${loginData.password}`); }; return ( <div className="login-panel"> <TextBox value={loginData.username} onChange={handleInputChange} /> <TextBox value={loginData.password} placeholder="Password" /> <Button label="Login" onClick={handleLogin} /> </div> ); }; // 使用示例 const App = () => { return ( <ControlledLoginPanel /> ); }; export default App;在这个例子中,ControlledLoginPanel 组件就是一个受控组件的例子,其中的输入框的值由 React 状态管理。
模态框控制: 当需要通过 props 控制模态框的显示或隐藏状态时,可以使用受控组件模式。
import React, { useState } from 'react'; const Button = ({ label, onClick }) => ( <button onClick={onClick}>{label}</button> ); const TextBox = ({ value, onChange, placeholder }) => ( <input type="text" value={value} onChange={onChange} placeholder={placeholder} /> ); // 自定义 Hook,处理登录表单逻辑 const useLoginForm = () => { const [loginData, setLoginData] = useState({ username: '', password: '' }); const handleInputChange = (e) => { const { name, value } = e.target; setLoginData((prevData) => ({ ...prevData, [name]: value, })); }; const handleLogin = () => { // 在这里实现登录逻辑 console.log(`使用用户名 ${loginData.username} 和密码 ${loginData.password} 登录`); }; return { loginData, handleInputChange, handleLogin, }; }; // 在组件中使用自定义 Hook const ControlledLoginPanel = () => { const { loginData, handleInputChange, handleLogin } = useLoginForm(); return ( <div className="login-panel"> <TextBox value={loginData.username} onChange={handleInputChange} placeholder="用户名" /> <TextBox value={loginData.password} onChange={handleInputChange} placeholder="密码" /> <Button label="登录" onClick={handleLogin} /> </div> ); }; // 使用示例 const App = () => { return ( <ControlledLoginPanel /> ); }; export default App;在这个例子中,我们将与登录表单相关的状态和逻辑抽离到一个自定义 useLoginForm Hook 中。使得 ControlledLoginPanel 组件更专注于渲染 UI,减少了状态和事件处理逻辑的混杂。
import React, { useState } from 'react'; const Button = ({ getLabel, handleClick }) => ( <button onClick={handleClick}>{getLabel()}</button> ); const TextBox = ({ getValue, onChange, placeholder }) => ( <input type="text" value={getValue()} onChange={onChange} placeholder={placeholder} /> ); const ControlledLoginPanel = ({ getUsernameProps, getPasswordProps, handleLogin }) => { return ( <div className="login-panel"> <TextBox {...getUsernameProps()} placeholder="Username" /> <TextBox {...getPasswordProps()} placeholder="Password" /> <Button getLabel={() => 'Login'} handleClick={handleLogin} /> </div> ); }; // 使用 Props Getters 模式的 Hooks const useLoginForm = () => { const [loginData, setLoginData] = useState({ username: '', password: '' }); const handleInputChange = (name) => (e) => { const { value } = e.target; setLoginData((prevData) => ({ ...prevData, [name]: value, })); }; const handleLogin = () => { // 实现登录逻辑 console.log(`Logging in with ${loginData.username} and ${loginData.password}`); }; const getUsernameProps = () => ({ getValue: () => loginData.username, onChange: handleInputChange('username'), }); const getPasswordProps = () => ({ getValue: () => loginData.password, onChange: handleInputChange('password'), }); return { getUsernameProps, getPasswordProps, handleLogin, }; }; // 使用示例 const App = () => { const { getUsernameProps, getPasswordProps, handleLogin } = useLoginForm(); return ( <ControlledLoginPanel getUsernameProps={getUsernameProps} getPasswordProps={getPasswordProps} handleLogin={handleLogin} /> ); }; export default App;在这个例子中,我们基于模式 3 进行了改造,把 ControlledLoginPanel 组件需要的 Props 通过函数的方式进行获取,以实现更灵活、更简便的组件复用。
减少嵌套层级: 相较于 Hooks 模式,Props Getters 模式可能减少了一些嵌套,使得组件结构更加扁平。
依赖外部 API: Props Getters 模式依赖外部传递的回调函数,可能导致一些依赖关系,不够自包含。
表单验证: 在一个表单组件中,通过 Props Getters 模式可以将表单验证的逻辑从组件中抽离,允许外部调用表单组件的验证函数,并获取验证结果。
import React, { useState } from 'react'; const TextInput = ({ getInputProps }) => { const inputProps = getInputProps(); return <input {...inputProps} />; }; const StateReducerExample = () => { // 初始状态为一个空字符串 const [inputValue, setInputValue] = useState(''); // stateReducer 函数用于处理状态的变化 const stateReducer = (state, changes) => { // 使用 switch case 处理不同的状态变化情况 switch (Object.keys(changes)[0]) { // 如果变化的是 value 属性 case 'value': // 如果输入的字符数量超过 10 个,则不允许变化 if (changes.value.length > 10) { return state; } break; // 可以添加其他 case 处理不同的状态变化 default: break; } // 返回新的状态 return { ...state, ...changes }; }; // 获取传递给子组件的 props const getInputProps = () => { return { value: inputValue, // 在输入框变化时调用 stateReducer 处理状态变化 onChange: (e) => setInputValue(stateReducer({ value: e.target.value })), }; }; return ( <div> <h3>State Reducer Example</h3> {/* 将获取的 props 传递给 TextInput 组件 */} <TextInput getInputProps={getInputProps} /> </div> ); }; export default StateReducerExample;在这个例子中,StateReducerExample 组件包含一个输入框,通过 getInputProps 函数将输入框的值和变化处理逻辑传递给 TextInput 组件。stateReducer 函数处理状态的变化,确保输入的字符数量不超过 10 个。
清晰的状态更新逻辑: 通过 stateReducer 可以清晰地看到每个状态变化是如何被处理的,使得状态更新逻辑更易于理解。
不适用于简单场景: 在简单场景下使用状态约减可能显得繁琐不必要。
控制状态更新流程: 在某些场景下,需要更灵活地控制状态更新的流程,例如在某个条件下阻止状态更新或根据条件进行额外的处理。