首页 > 解决方案 > 输入时反应路由器v4输入组件失去焦点

问题描述

我正在使用反应路由器 v4 并使用渲染道具来加载具有动态输入的设置组件(基于具有 onChange 处理程序的状态的值道具)。当我在不使用反应路由器的情况下加载组件时,在输入字段中输入是动态的,并且在您输入时会更改状态。但是当我使用反应路由器时,每个字符按下都会重新渲染整个设置组件,导致输入字段失去焦点。不知道为什么会发生这种情况,因为我在组件上使用的是渲染道具而不是组件道具<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;

标签: javascriptreactjsreact-router-v4

解决方案


推荐阅读