这个问题与material-ui
<TextField>
组件有关,但是解决方案很可能在React本身中找到。
想象一下我们正在做一个简单的登录表单。登录表单由状态机表示。
{
empty: {},
filled: { typing, authenticating }
}
我有一个<LoginForm>
组件,它呈现了两个<TextField>
组件和一个<Button>
。第一个<TextField>
会自动对焦于安装座。很简单。
我有一个父组件来管理机器的当前状态,并根据其值呈现不同的组件,如下所示:
<Empty>
组件,用于通过特定道具渲染<LoginForm>
<Wrapper>
个组件-等效于<Fragment>
filled
下的任何状态都呈现为<Wrapper>
的子级。
<Typing>
组件,它使用不同的道具渲染<LoginForm>
<Authenticating>
组件,用于呈现微调器。empty
组件中的一个不再为空时, filled
的状态转换为<TextBox>
。
问题:
想象一下,我们从empty
状态开始。它会渲染<Empty>
,后者会渲染<LoginForm>
,后者会使用自动对焦来渲染用户名<TextField>
。
我们专注于用户名输入并开始输入。一切都很好。
但是,假设我们首先开始输入密码(即第二个<TextBox>
不会自动对焦)。我们从empty
状态开始,输入密码的第一个字母,然后过渡到filled>typing
状态,该状态似乎已重新安装<LoginForm>
并再次自动聚焦于用户名输入。结果是您可以输入密码的第一个字母,并且由于重新自动聚焦,后续的字母会添加到用户名输入中。
我认为,由于react产生的标记本质上是相同的(由于包装器组件本身没有呈现),因此不会进行重新挂载,因此我们只能在第一次挂载时获得自动聚焦(即从empty
开始。
我该如何解决?
答案 0 :(得分:0)
之前(问题代码):
const LoginMachineDelegator = () => {
const props = {
machine: init.machine,
render: {
[init.STATES.EMPTY]: Empty,
[init.STATES.FILLED]: Wrapper,
[init.STATES.TYPING]: Typing,
[init.STATES.AUTHENTICATING]: Authenticating
}
}
return <MachineDelegator {...props}/>;
}
处于empty
状态的反应组件树:
MachineDelegator > Empty > LoginForm
处于filled>typing
状态的反应组件树:
MachineDelegator > Wrapper > Typing > LoginForm
之后(对帐代码):
const LoginMachineDelegator = () => {
const props = {
machine: init.machine,
[init.STATES.EMPTY]: { func: createEmptyLoginForm },
[init.STATES.FILLED]: { /* no element */ },
[init.STATES.TYPING]: { func: createTypingLoginForm },
[init.STATES.AUTHENTICATING]: { component: Authentication }
}
}
由于函数返回了react元素,因此它们本身不会插入React组件树中。相反,返回元素是。这样,新的组件树将如下所示:
处于empty
状态时:
MachineDelegator > LoginForm
处于filled>typing
状态时:
MachineDelegator > LoginForm
这确保LoginForm不会被重新挂载和重新呈现