我使用反应路由器v4并使用渲染道具来加载具有动态输入的设置组件(基于具有onChange处理程序的状态的值prop)。当我在不使用react路由器的情况下加载组件时,在输入字段中输入是动态的,并在键入时更改状态。但是当我使用反应路由器时,每个字符都会重新渲染整个设置组件,导致输入字段失去焦点。不确定为什么会发生这种情况,因为我在<Route />
组件上使用了渲染道具而不是组件道具。任何帮助将不胜感激!
我的应用组件:
import React, { Component, Fragment } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import Home from "../Home/Home";
import Header from "../Header/Header";
import AppSettings from "../AppSettings/AppSettings";
import NotFound from "../NotFound/NotFound";
import { secsToMs, minsToMs, msToTime } from "../../helpers";
import "./App.css";
class App extends Component {
state = {
settings: {
time: {
break: minsToMs(5),
relax: minsToMs(15),
work: minsToMs(25)
},
trackLength: 2,
autoplay: true
},
defaultSettings: {
time: {
break: minsToMs(5),
relax: minsToMs(15),
work: minsToMs(25)
},
trackLength: 4,
autoplay: false
},
time: minsToMs(25),
totalTime: minsToMs(25),
timerPlaying: false,
track: {
tasksCompleted: 0,
breaksCompleted: 0,
timerName: "work"
}
};
updateSettings = (key, updatedSetting) => {
let settings = { ...this.state.settings };
settings.time[key] = updatedSetting;
this.setState({ settings });
};
//...other App methods
render() {
const MainAppContent = ({ location }) => (
<Fragment>
<Header track={this.state.track} location={location} />
<Home
timerPlaying={this.state.timerPlaying}
totalTime={this.state.totalTime}
time={this.state.time}
track={this.state.track}
trackLength={this.state.settings.trackLength}
startTimer={this.startTimer}
pauseTimer={this.pauseTimer}
resetTimer={this.resetTimer}
skipTimer={this.skipTimer}
/>
<AppSettings
settings={this.state.settings}
updateSettings={this.updateSettings}
restoreDefaultSettings={this.restoreDefaultSettings}
/>
</Fragment>
);
const SettingsAppContent = ({ location }) => (
<Fragment>
<Header track={this.state.track} location={location} />
<AppSettings
settings={this.state.settings}
updateSettings={this.updateSettings}
restoreDefaultSettings={this.restoreDefaultSettings}
/>
</Fragment>
);
return (
<main className="App">
<BrowserRouter>
<Switch>
<Route exact path="/" component={MainAppContent} />
<Route
path="/settings"
render={props => <SettingsAppContent {...props} />}
/>
<Route component={NotFound} />
</Switch>
</BrowserRouter>
</main>
);
}
}
export default App;
我的AppSettings组件:
import React, { Component, Fragment } from "react";
import RangeSlider from "../RangeSlider/RangeSlider";
import { minsToMs } from "../../helpers";
import "./AppSettings.css";
class Settings extends Component {
render() {
return (
<Fragment>
<h1>Settings</h1>
{Object.keys(this.props.settings.time).map(key => (
<RangeSlider
name={key}
key={key}
time={this.props.settings.time[key]}
updateSettings={this.props.updateSettings}
/>
))}
<button onClick={this.props.restoreDefaultSettings}>
Revert to Default
</button>
</Fragment>
);
}
}
export default Settings;
我的输入组件:
import React, { Component } from "react";
import { msToTime, minsToMs } from "../../helpers";
import "./RangeSlider.css";
class RangeSlider extends Component {
onSettingsChange = e => {
let rangeValue = parseInt(e.currentTarget.value);
if (rangeValue > 60) {
rangeValue = 60;
} else if (rangeValue < 1 || rangeValue === NaN) {
rangeValue = 1;
}
let rangeValueMs = minsToMs(rangeValue);
let key = e.currentTarget.name;
let updatedSetting = rangeValueMs;
const updatedSettings = {
...this.props.settings,
[key]: rangeValueMs
};
console.log("updatedSettings", updatedSettings);
this.props.updateSettings(key, updatedSetting);
};
render() {
const { name, time } = this.props;
return (
<div>
<input
type="number"
min="1"
max="60"
value={msToTime(time).m}
className="text-box"
name={name}
onChange={this.onSettingsChange}
/>
</div>
);
}
}
export default RangeSlider;