gpt4 book ai didi

javascript - React-Loadable 重新渲染导致输入失去焦点

转载 作者:行者123 更新时间:2023-11-30 14:31:02 25 4
gpt4 key购买 nike

我遇到了一个问题 react-loadable导致我的输入组件之一在状态更新后重新呈现并失去焦点。我已经做了一些挖掘,但找不到其他人遇到这个问题,所以我认为我在这里遗漏了一些东西。

我正在尝试使用 react-loadable根据用户选择的主题将组件动态包含到我的应用程序中。这工作正常。

./components/App

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;

./components/AdminPanel

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 />组件看起来像:

./themes/Default/components/SideBar

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;

./components/ThemeSettingPanel

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;

./containers/ThemeSetting

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);

./component/ThemeSetting

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;

./components/common/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从重新渲染?

编辑:Here是请求的 repo 链接。

最佳答案

编辑:根据评论中的对话,我很抱歉,我误读了这个问题。此处的答案已更新(更新后的答案下方为原始答案)

更新的答案

从查看 react-loadable docs ,看起来 Loadable HOC 旨在在 render 方法之外调用。在您的例子中,您正在 AdminPanel 的渲染方法中加载 ThemedSideBar。我怀疑你的 TextEdit 输入的变化,传递来更新你的 Redux 状态,然后通过组件链传回导致 React 考虑重新渲染 AdminPanel。因为您对 Loadable 的调用是在 render 方法中(即 AdminPanel 是一个展示组件),react-loadable每次 React 访问该代码路径时,都会呈现一个全新的加载组件。因此,React 认为它需要销毁先前的组件,以适本地使组件与新 Prop 保持同步。

这个有效:

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

FormControlvalue={value}onChange 处理程序作为 Prop 。这意味着您已表明它是一个受控(而不是 uncontrolled)组件。

如果您希望该字段在用户键入输入时采用更新的值,您需要传播 onChange 处理程序捕获的更改,并确保它被反馈到value={value} 属性。

现在,看起来 value 将始终等于 theme.settings.Height 或类似内容(大概为 null/空)。

另一种方法是使 FormControl 成为不受控制的组件,但我猜你不想那样做。

关于javascript - React-Loadable 重新渲染导致输入失去焦点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51163746/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com