我遇到了一个问题,react-loadable导致我的一个输入组件在状态更新后重新呈现并失去焦点。我已经做了一些调查,我找不到有这个问题的其他人,所以我想我在这里遗漏了一些东西。
我试图根据用户选择的主题使用react-loadable动态地将组件包含到我的应用程序中。这很好用。
/组件/应用程序
import React from 'react';
import Loadable from 'react-loadable';
/**
* Import Containers
*/
import AdminBar from '../../containers/AdminBar';
import AdminPanel from '../../components/AdminPanel';
import 'bootstrap/dist/css/bootstrap.css';
import './styles.css';
const App = ({ isAdmin, inEditMode, theme }) => {
const MainContent = Loadable({
loader: () => import('../../themes/' + theme.name + '/components/MainContent'),
loading: () => (<div>Loading...</div>)
});
const Header = Loadable({
loader: () => import('../../themes/' + theme.name + '/components/Header'),
loading: () => (<div>Loading...</div>)
});
return (
<div>
{
(isAdmin) ? <AdminBar
className='admin-bar'
inEditMode={inEditMode} /> : ''
}
<Header
themeSettings={theme.settings.Header} />
<div className='container-fluid'>
<div className='row'>
{
(isAdmin && inEditMode) ? <AdminPanel
className='admin-panel'
theme={theme} /> : ''
}
<MainContent
inEditMode={inEditMode} />
</div>
</div>
</div>
);
};
export default App;./构成部分/管理小组
import React from 'react';
import Loadable from 'react-loadable';
import './styles.css';
const AdminPanel = ({ theme }) => {
const ThemedSideBar = Loadable({
loader: () => import('../../themes/' + theme.name + '/components/SideBar'),
loading: () => null
});
return (
<div className='col-sm-3 col-md-2 sidebar'>
<ThemedSideBar
settings={theme.settings} />
</div>
);
};
export default AdminPanel;这就是我的<ThemedSideBar />组件的样子:
/主题/默认/组件/侧栏
import React from 'react';
import ThemeSettingPanel from '../../../../components/ThemeSettingPanel';
import ThemeSetting from '../../../../containers/ThemeSetting';
import './styles.css';
const SideBar = ({ settings }) => {
return (
<ThemeSettingPanel
name='Header'>
<ThemeSetting
name='Background Color'
setting={settings.Header}
type='text'
parent='Header' />
<ThemeSetting
name='Height'
setting={settings.Header}
type='text'
parent='Header' />
</ThemeSettingPanel>
);
};
export default SideBar;/组件/主题设置小组
import React from 'react';
import { PanelGroup, Panel } from 'react-bootstrap';
const ThemeSettingPanel = ({ name, children }) => {
return (
<PanelGroup accordion id='sidebar-accordion-panelGroup'>
<Panel>
<Panel.Heading>
<Panel.Title toggle>{name}</Panel.Title>
</Panel.Heading>
<Panel.Body collapsible>
{children}
</Panel.Body>
</Panel>
</PanelGroup>
);
};
export default ThemeSettingPanel;./容器/主题设置
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { themeSettingChange } from '../App/actions';
import ThemeSetting from '../../components/ThemeSetting';
class ThemeSettingContainer extends Component {
constructor(props) {
super(props);
this.handleOnChange = this.handleOnChange.bind(this);
}
handleOnChange(name, parent, value) {
const payload = {
name: name,
parent,
value: value
};
this.props.themeSettingChange(payload);
}
render() {
return (
<ThemeSetting
name={this.props.name}
setting={this.props.setting}
parent={this.props.parent}
type={this.props.type}
handleOnChange={this.handleOnChange} />
);
}
}
//----Redux Mappings----//
const mapStateToProps = (state) => ({
});
const mapDispatchToProps = {
themeSettingChange: (value) => themeSettingChange(value)
};
export default connect(mapStateToProps, mapDispatchToProps)(ThemeSettingContainer);/组件/主题设置
import React from 'react';
import TextField from '../common/TextField';
import './styles.css';
const ThemeSetting = ({ name, setting, type, parent, handleOnChange }) => {
return (
<div className='row theme-setting'>
<div className='col-xs-7'>
{name}
</div>
<div className='col-xs-5'>
{
generateField(type, setting, name, parent, handleOnChange)
}
</div>
</div>
);
};
function generateField(type, setting, name, parent, handleOnChange) {
const value = setting ? setting[name] : '';
switch (type) {
case 'text':
return <TextField
value={value}
name={name}
parent={parent}
handleOnChange={handleOnChange} />;
default:
break;
}
}
export default ThemeSetting;/组件/公共/TextField
import React from 'react';
import { FormControl } from 'react-bootstrap';
const TextField = ({ value, name, parent, handleOnChange }) => {
return (
<FormControl
type='text'
value={value}
onChange={(e) => {
handleOnChange(name, parent, e.target.value);
}} />
);
};
export default TextField;当更新“我的管理面板”中的字段时,会触发状态更改。这似乎触发了react-loadable重新呈现我的<ThemedSideBar />组件,这破坏了我的输入,并创建了一个具有更新值的新输入。还有其他人有这个问题吗?有办法阻止react-loadable重新呈现吗?
编辑:这里是到回购请求的链接。
发布于 2018-07-04 01:09:19
编辑:根据评论中的对话,很抱歉,我误解了这个问题。这里的答案是更新的(原来的答案在更新的答案下面)
更新答复
从react可加载文档的角度来看,可加载的自组织似乎是要在render方法之外调用的。在您的示例中,您将ThemedSideBar加载到AdminPanel的呈现方法中。我怀疑您的TextEdit输入的更改,传递到更新您的Redux状态,然后通过组件链返回,导致考虑重新呈现AdminPanel。因为您对Loadable的调用在render方法中(即AdminPanel是表示组件),react-loadable每次响应到该代码路径时都会呈现一个全新的加载组件。因此,React认为需要销毁之前的组件,以便适当地更新组件与新的props。
这样做是可行的:
import React from 'react';
import Loadable from 'react-loadable';
import './styles.css';
const ThemedSideBar = Loadable({
loader: () => import('../../themes/Default/components/SideBar'),
loading: () => null
});
const AdminPanel = ({ theme }) => {
return (
<div className='col-sm-3 col-md-2 sidebar'>
<ThemedSideBar
settings={theme.settings} />
</div>
);
};
export default AdminPanel;
原始答案
看起来,您的问题可能与您构建TextField而不是react-loadable的方式有关。
FormControl将value={value}和onChange处理程序作为道具。这意味着您已经表明它是一个受控组件(相对于不受控制)。
如果希望字段在用户输入时接受更新的值,则需要传播onChange处理程序捕获的更改,并确保将其反馈给value={value}支柱中的值。
现在,看起来value总是等于theme.settings.Height等(大概为空/空)。
另一种选择是使FormControl成为一个不受控制的组件,但我猜您不想这样做。
https://stackoverflow.com/questions/51163746
复制相似问题