reactjs - React - 将孩子分成几部分
问题描述
理念
我正在尝试创建一个被拆分为多个部分的组件。
例如,在下面的示例代码中,我的目标是在保持状态的同时将表单和操作分开。这样,我可以创建一个基本的表单+操作按钮组件,然后在不同的页面上设置不同的样式。
import { useState } from 'react'
const FormBasic = ({ children }) => {
const [ text, setText ] = useState('')
const onSubmit = () => console.log("Submitting");
const onChange = (e) => {
console.log("Typing", e.target.value);
setText(e.target.value)
}
const Form = () => <textarea rows={4} onChange={onChange} value={text} />;
const Actions = () => <button onClick={onSubmit}>Some Buttons</button>;
return children({ Form, Actions });
};
export default FormBasic;
问题
然后我将以这种方式使用它(如下)。问题是 - 对于静态组件来说,这一切都很好,但你会在状态改变的那一刻开始看到问题。
例如,当我输入<textarea />
andonChanged
被触发时,函数会重新呈现,并且您会失去对文本区域的关注。所以最终你不能真正输入文本区域。
export default function App() {
return (
<FormBasic>
{({ Form, Actions }) => {
return (<React.Fragment>
<div style={{ border: '1px solid red'}}>
<Form />
</div>
<div style={{ border: '1px solid blue'}}>
<Actions />
</div>
</React.Fragment>)
}}
</FormBasic>
);
}
我包括一个代码沙箱 - https://codesandbox.io/s/solitary-brook-nrrbf?file=/src/App.js
问题
这类组件的实际使用可能存在疑问。实际上,我如何修改我的代码,以便我可以继续使用导出的textarea
.
或者是否有其他形式的导出组件以便我可以拆分它们并维护状态?
或者上述风格是否可能?
PS:我用过context和redux,在这个例子中我尽量不使用它们。我试图保持简单。
解决方案
您的问题的一种解决方案是:使用 React Context API代替传递text
和setText
作为道具。
具体来说:
FormBasic
将成为状态+上下文提供者。Form
并将Actions
成为上下文消费者。- 上下文将包含状态 + 状态设置器。
这是我想出的(CodeSandbox 上的工作示例):
(我为状态变量使用了更通用的名称来帮助这篇文章的其他读者)。
import React from "react";
import { useState, useContext, createContext } from "react";
// create the context with some generic defaults
const StateContext = createContext({
state: "",
setState: v => v
});
// create the context hook
const useStateContext = () => useContext(StateContext);
// the textarea component
const Form = () => {
const { state, setState } = useStateContext();
const onChange = (e) => {
console.log("Typing", e.target.value);
setState(e.target.value);
};
return <textarea rows={4} onChange={onChange} value={state} />;
};
// the buttons component
const Actions = () => {
const { state } = useStateContext();
const onSubmit = () => {
alert(state);
};
return <button onClick={onSubmit}>Some Buttons</button>;
};
// the form itself holding state and the context provider
const FormBasic = ({ children }) => {
const [state, setState] = useState("");
return (
<StateContext.Provider value={{ state, setState }}>
{children}
</StateContext.Provider>
);
};
const App = () => {
return (
<FormBasic>
<div style={{ border: "1px solid red" }}>
<Form />
</div>
<div style={{ border: "1px solid blue" }}>
<Actions />
</div>
</FormBasic>
);
};
请注意,FormBasic
不再需要有children
as 函数,或者包含在 中的内容React.Fragment
,使代码更干净。您可以直接使用上下文消费者。
推荐阅读
- html - 图中的“可聚焦元素应具有交互式语义”是什么意思?
- c# - 测试 .net core 2.2 web api 控制器时收到 InvalidOperationException 错误
- angular - 我应该取消订阅 observable 以防万一吗?
- java - 使用 spring 设置 REST api
- javascript - 使用 javascript 从 vue 组件导出渲染的 html
- sql - 在数据透视查询中查找总数的百分比
- laravel - 如何计算角色=学习者的用户数?
- javascript - 突出显示 HTML 表格的行数据差异
- google-sheets - 谷歌表格 - 将一个值加入逗号分隔列表中的每个值,并生成一个结果列表
- postgresql - 有没有办法让 Postgres 提交超时?